diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 3d9f4fe..0000000 --- a/.gitignore +++ /dev/null @@ -1,15 +0,0 @@ -*.o -test-sdl -.ycm_extra_conf.py -local-data -.clangd/ -.cache/ -.gdb_history -compile_commands.json -switches.local -TODO -bench-debug -debug -sofis -testbench/* -!testbench/*.c diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 45f6ba4..0000000 --- a/.gitmodules +++ /dev/null @@ -1,13 +0,0 @@ -[submodule "sdl-pcf"] - path = sdl-pcf - url = https://github.com/sam-itt/sdl-pcf -[submodule "fg-io"] - path = fg-io - url = https://github.com/sam-itt/fg-io.git - shallow = true -[submodule "fg-roam"] - path = fg-roam - url = https://github.com/sam-itt/fg-roam.git -[submodule "sensors/bno080"] - path = sensors/bno080 - url = https://github.com/sam-itt/bno080 diff --git a/COPYING b/COPYING deleted file mode 120000 index 670f485..0000000 --- a/COPYING +++ /dev/null @@ -1 +0,0 @@ -LICENCE.md \ No newline at end of file diff --git a/LICENCE.md b/LICENCE.md deleted file mode 100644 index b017086..0000000 --- a/LICENCE.md +++ /dev/null @@ -1,264 +0,0 @@ -The GNU General Public License, Version 2, June 1991 (GPLv2) -============================================================ - -> Copyright (C) 1989, 1991 Free Software Foundation, Inc. -> 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - -Everyone is permitted to copy and distribute verbatim copies of this license -document, but changing it is not allowed. - - -Preamble --------- - -The licenses for most software are designed to take away your freedom to share -and change it. By contrast, the GNU General Public License is intended to -guarantee your freedom to share and change free software--to make sure the -software is free for all its users. This General Public License applies to most -of the Free Software Foundation's software and to any other program whose -authors commit to using it. (Some other Free Software Foundation software is -covered by the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - -When we speak of free software, we are referring to freedom, not price. Our -General Public Licenses are designed to make sure that you have the freedom to -distribute copies of free software (and charge for this service if you wish), -that you receive source code or can get it if you want it, that you can change -the software or use pieces of it in new free programs; and that you know you can -do these things. - -To protect your rights, we need to make restrictions that forbid anyone to deny -you these rights or to ask you to surrender the rights. These restrictions -translate to certain responsibilities for you if you distribute copies of the -software, or if you modify it. - -For example, if you distribute copies of such a program, whether gratis or for a -fee, you must give the recipients all the rights that you have. You must make -sure that they, too, receive or can get the source code. And you must show them -these terms so they know their rights. - -We protect your rights with two steps: (1) copyright the software, and (2) offer -you this license which gives you legal permission to copy, distribute and/or -modify the software. - -Also, for each author's protection and ours, we want to make certain that -everyone understands that there is no warranty for this free software. If the -software is modified by someone else and passed on, we want its recipients to -know that what they have is not the original, so that any problems introduced by -others will not reflect on the original authors' reputations. - -Finally, any free program is threatened constantly by software patents. We wish -to avoid the danger that redistributors of a free program will individually -obtain patent licenses, in effect making the program proprietary. To prevent -this, we have made it clear that any patent must be licensed for everyone's free -use or not licensed at all. - -The precise terms and conditions for copying, distribution and modification -follow. - - -Terms And Conditions For Copying, Distribution And Modification ---------------------------------------------------------------- - -**0.** This License applies to any program or other work which contains a notice -placed by the copyright holder saying it may be distributed under the terms of -this General Public License. The "Program", below, refers to any such program or -work, and a "work based on the Program" means either the Program or any -derivative work under copyright law: that is to say, a work containing the -Program or a portion of it, either verbatim or with modifications and/or -translated into another language. (Hereinafter, translation is included without -limitation in the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not covered by -this License; they are outside its scope. The act of running the Program is not -restricted, and the output from the Program is covered only if its contents -constitute a work based on the Program (independent of having been made by -running the Program). Whether that is true depends on what the Program does. - -**1.** You may copy and distribute verbatim copies of the Program's source code -as you receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice and -disclaimer of warranty; keep intact all the notices that refer to this License -and to the absence of any warranty; and give any other recipients of the Program -a copy of this License along with the Program. - -You may charge a fee for the physical act of transferring a copy, and you may at -your option offer warranty protection in exchange for a fee. - -**2.** You may modify your copy or copies of the Program or any portion of it, -thus forming a work based on the Program, and copy and distribute such -modifications or work under the terms of Section 1 above, provided that you also -meet all of these conditions: - -* **a)** You must cause the modified files to carry prominent notices stating - that you changed the files and the date of any change. - -* **b)** You must cause any work that you distribute or publish, that in whole - or in part contains or is derived from the Program or any part thereof, to - be licensed as a whole at no charge to all third parties under the terms of - this License. - -* **c)** If the modified program normally reads commands interactively when - run, you must cause it, when started running for such interactive use in the - most ordinary way, to print or display an announcement including an - appropriate copyright notice and a notice that there is no warranty (or - else, saying that you provide a warranty) and that users may redistribute - the program under these conditions, and telling the user how to view a copy - of this License. (Exception: if the Program itself is interactive but does - not normally print such an announcement, your work based on the Program is - not required to print an announcement.) - -These requirements apply to the modified work as a whole. If identifiable -sections of that work are not derived from the Program, and can be reasonably -considered independent and separate works in themselves, then this License, and -its terms, do not apply to those sections when you distribute them as separate -works. But when you distribute the same sections as part of a whole which is a -work based on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the entire whole, -and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest your -rights to work written entirely by you; rather, the intent is to exercise the -right to control the distribution of derivative or collective works based on the -Program. - -In addition, mere aggregation of another work not based on the Program with the -Program (or with a work based on the Program) on a volume of a storage or -distribution medium does not bring the other work under the scope of this -License. - -**3.** You may copy and distribute the Program (or a work based on it, under -Section 2) in object code or executable form under the terms of Sections 1 and 2 -above provided that you also do one of the following: - -* **a)** Accompany it with the complete corresponding machine-readable source - code, which must be distributed under the terms of Sections 1 and 2 above on - a medium customarily used for software interchange; or, - -* **b)** Accompany it with a written offer, valid for at least three years, to - give any third party, for a charge no more than your cost of physically - performing source distribution, a complete machine-readable copy of the - corresponding source code, to be distributed under the terms of Sections 1 - and 2 above on a medium customarily used for software interchange; or, - -* **c)** Accompany it with the information you received as to the offer to - distribute corresponding source code. (This alternative is allowed only for - noncommercial distribution and only if you received the program in object - code or executable form with such an offer, in accord with Subsection b - above.) - -The source code for a work means the preferred form of the work for making -modifications to it. For an executable work, complete source code means all the -source code for all modules it contains, plus any associated interface -definition files, plus the scripts used to control compilation and installation -of the executable. However, as a special exception, the source code distributed -need not include anything that is normally distributed (in either source or -binary form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component itself -accompanies the executable. - -If distribution of executable or object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the source code -from the same place counts as distribution of the source code, even though third -parties are not compelled to copy the source along with the object code. - -**4.** You may not copy, modify, sublicense, or distribute the Program except as -expressly provided under this License. Any attempt otherwise to copy, modify, -sublicense or distribute the Program is void, and will automatically terminate -your rights under this License. However, parties who have received copies, or -rights, from you under this License will not have their licenses terminated so -long as such parties remain in full compliance. - -**5.** You are not required to accept this License, since you have not signed -it. However, nothing else grants you permission to modify or distribute the -Program or its derivative works. These actions are prohibited by law if you do -not accept this License. Therefore, by modifying or distributing the Program (or -any work based on the Program), you indicate your acceptance of this License to -do so, and all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - -**6.** Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the original -licensor to copy, distribute or modify the Program subject to these terms and -conditions. You may not impose any further restrictions on the recipients' -exercise of the rights granted herein. You are not responsible for enforcing -compliance by third parties to this License. - -**7.** If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), conditions -are imposed on you (whether by court order, agreement or otherwise) that -contradict the conditions of this License, they do not excuse you from the -conditions of this License. If you cannot distribute so as to satisfy -simultaneously your obligations under this License and any other pertinent -obligations, then as a consequence you may not distribute the Program at all. -For example, if a patent license would not permit royalty-free redistribution of -the Program by all those who receive copies directly or indirectly through you, -then the only way you could satisfy both it and this License would be to refrain -entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply and the -section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any patents or -other property right claims or to contest validity of any such claims; this -section has the sole purpose of protecting the integrity of the free software -distribution system, which is implemented by public license practices. Many -people have made generous contributions to the wide range of software -distributed through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing to -distribute software through any other system and a licensee cannot impose that -choice. - -This section is intended to make thoroughly clear what is believed to be a -consequence of the rest of this License. - -**8.** If the distribution and/or use of the Program is restricted in certain -countries either by patents or by copyrighted interfaces, the original copyright -holder who places the Program under this License may add an explicit -geographical distribution limitation excluding those countries, so that -distribution is permitted only in or among countries not thus excluded. In such -case, this License incorporates the limitation as if written in the body of this -License. - -**9.** The Free Software Foundation may publish revised and/or new versions of -the General Public License from time to time. Such new versions will be similar -in spirit to the present version, but may differ in detail to address new -problems or concerns. - -Each version is given a distinguishing version number. If the Program specifies -a version number of this License which applies to it and "any later version", -you have the option of following the terms and conditions either of that version -or of any later version published by the Free Software Foundation. If the -Program does not specify a version number of this License, you may choose any -version ever published by the Free Software Foundation. - -**10.** If you wish to incorporate parts of the Program into other free programs -whose distribution conditions are different, write to the author to ask for -permission. For software which is copyrighted by the Free Software Foundation, -write to the Free Software Foundation; we sometimes make exceptions for this. -Our decision will be guided by the two goals of preserving the free status of -all derivatives of our free software and of promoting the sharing and reuse of -software generally. - - -No Warranty ------------ - -**11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR -THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE -STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM -"AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, -BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - -**12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR -INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA -BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER -OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. diff --git a/Makefile b/Makefile deleted file mode 100644 index ffd19a6..0000000 --- a/Makefile +++ /dev/null @@ -1,91 +0,0 @@ -include switches.defaults -sinclude switches.local - -# Where to find resources/{fg-scenery,skybox} and shaders/ -FGR_HOME=\"./fg-roam/src\" -SFS_HOME=\".\" - -SRCDIR=. -TBDIR=$(SRCDIR)/testbench -FG_IO=$(SRCDIR)/fg-io -FGCONN=$(FG_IO)/flightgear-connector -FGTAPE=$(FG_IO)/fg-tape -FG_ROAM=$(SRCDIR)/fg-roam -CGLM=$(FG_ROAM)/lib/cglm/include -BNO080=$(SRCDIR)/sensors/bno080 - -ifeq ($(BUILD_MODE),debug) - OPT_CFLAGS=-O0 -g3 -else - OPT_CFLAGS=-O2 -endif - -CC=gcc -CFLAGS=$(OPT_CFLAGS) `pkg-config glib-2.0 sdl2 SDL2_image libgps --cflags` \ - -I$(SRCDIR) \ - -I$(SRCDIR)/widgets \ - -I$(SRCDIR)/dialogs \ - -I$(SRCDIR)/sdl-pcf/src \ - -I$(FGCONN) \ - -I$(FGTAPE) \ - -I$(BNO080) \ - -I$(CGLM) \ - -I$(FG_ROAM)/src \ - -DUSE_SGPU_TEXTURE=1 \ - -DUSE_SDL_GPU=1 \ - -DENABLE_DEBUG_TRIANGLE=0 \ - -DENABLE_DEBUG_CUBE=0 \ - -DFGR_HOME=$(FGR_HOME) \ - -DSFS_HOME=$(SFS_HOME) \ - -DBNO080_DEV=$(BNO080_DEV) \ - -DENABLE_MOCK_GPS=$(ENABLE_MOCK_GPS) \ - -DENABLE_PERF_COUNTERS=1 \ - -DUSE_GLES=$(USE_GLES) \ - -DENABLE_3D=$(ENABLE_3D) \ - -DNO_PRELOAD=$(NO_PRELOAD) \ - -DUSE_TINY_TEXTURES=$(TINY_TEXTURES) \ - -DHAVE_MKDIR_P \ - -DHAVE_CREATE_PATH \ - -DHAVE_HTTP_DOWNLOAD_FILE \ - -DHAVE_IGN_OACI_MAP=$(HAVE_IGN_OACI_MAP) -LDFLAGS=-lz -lm `pkg-config glib-2.0 sdl2 SDL2_image libgps --libs` -Wl,--as-needed -lSDL2_gpu -l$(GL_LIB) -lpthread -lcurl -EXEC=sofis -SRC= $(filter-out $(SRCDIR)/main.c, $(wildcard $(SRCDIR)/*.c)) -SRC+= $(wildcard $(SRCDIR)/widgets/*.c) -SRC+= $(wildcard $(SRCDIR)/dialogs/*.c) -SRC+= $(wildcard $(SRCDIR)/sdl-pcf/src/*.c) -SRC+= $(filter-out $(FGCONN)/fg-connector-test.c, $(wildcard $(FGCONN)/*.c)) -SRC+= $(filter-out $(FGTAPE)/fg-tape-reader.c, $(wildcard $(FGTAPE)/*.c)) -SRC+= $(wildcard $(SRCDIR)/sensors/*.c) -SRC+= $(filter-out $(BNO080)/test.c, $(wildcard $(BNO080)/*.c)) -ifeq ($(ENABLE_3D), 1) -SRC+= $(filter-out $(FG_ROAM)/src/view-gl.c, $(wildcard $(FG_ROAM)/src/*.c)) -endif -OBJ= $(SRC:.c=.o) -MAIN_OBJ=main.o - -TB_SRC := $(wildcard $(TBDIR)/*.c) -TB_BIN := $(TB_SRC:.c=) - -all: $(EXEC) - -$(EXEC): $(OBJ) $(MAIN_OBJ) - $(CC) -o $@ $^ $(LDFLAGS) - -# Build each test bench executable -$(TB_BIN): %: %.c $(OBJ) - $(CC) $(CFLAGS) $< $(OBJ) $(LDFLAGS) $(LDLIBS) -o $@ - -testbench: $(TB_BIN) - -%.o: %.c - $(CC) -o $@ -c $< $(CFLAGS) - -.PHONY: clean mrproper - -clean: - rm -rf *.o sdl-pcf/src/*.o fg-roam/src/*.o fg-io/fg-tape/*.o sensors/*.o widgets/*.o dialogs/*.o testbench/*.o - -mrproper: clean - rm -rf $(EXEC) - diff --git a/README.md b/README.md deleted file mode 100644 index ca6cd35..0000000 --- a/README.md +++ /dev/null @@ -1,343 +0,0 @@ -# SoFIS - Open Source EFIS for your Experimental, Ultralight and Simulator - -SoFIS aims at providing a full EFIS experience using off the shelf components. - -SoFIS is written in C, from scratch, with minimal dependencies. - -Still in the early stages of development it can already show your situation and -attitude. It currently supports reading pre-recording flight data, getting -real time data from FlightGear over the network, from a [Stratux][7] unit, and -finaly from a couple of sensors. - -Running a pre-recorded (circuit) flight from LFLG (Grenoble, France): - -![lflg circuit][1] - -Doing a direct-to from LFLG to LFMA (Aix-en-provance, France): - -![ddt-lfma][9] - -Controls are currently mapped to keyboard keys: -* g to show the dialog -* , , , : Contextual moves in the controls (scroll, change text, etc.) -* Enter Validate - -Those controls will be mapped to a two-ring-plus-button rotatry encoder. Think -as the left/right arrow being one of the ring, up/down the other one and enter -the button click. - -Mini-map current keyboard controls are as follows: -* Keypad arrow keys: Move the map -* Keypad /: Center the map on plane -* Keypad +: Zoom in -* Keypad -: Zoom out - -Running on the very first Raspberry Pi: - -![raspberry][2] - -## Building from source - -### Dependencies - -While development has mainly been done on a Gentoo system, SoFIS is not aimed at a specific distro. Here are the generic package names required to build/run SoFIS: -* SDL2 -* SDL2_Image -* [SDL_gpu][3] -* Glib (Only GArray and GPtrArray are really used/needed) -* libcurl -* libgps - -If you don't want 3D synthetic vision you won't need glib and SDL_gpu. Just set -`ENABLE_3D=0` in switches.local - -> [!TIP] -> The following command should give you a comparable output: -> ```sh -> $ pkg-config glib-2.0 sdl2 SDL2_image libgps --cflags -> -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/SDL2 -D_REENTRANT -> ``` - -Please note that the project is still in early stages and doesn't have a -fully-fledged build system (autotools is in the works) that can detect -everything for you. You'll need to resort to `Makefile` (and `switches.local`) -editing for the time being. - -##### Distro-specific packages - -Apart from the Gentoo system on which dev+testing has been done, this section will lists packages that provide the required dependencies on various distro where users have reported successful build and run. - -###### Debian-based (Ubuntu and derivatives) - -Packages to install before the build: -* build-essential -* cmake -* pkg-config -* git - -```sh -$ sudo apt-get install build-essential cmake pkg-config git -``` - -Packages providing dependencies: -* libcurl4-gnutls-dev -* gpsd -* libgps-dev -* libsdl2-dev -* libsdl2-image-dev -* libglib2.0-dev - -```sh -$ sudo apt-get install libcurl4-gnutls-dev gpsd libgps-dev libsdl2-dev libsdl2-image-dev libglib2.0-dev -``` - -### Building - -> [!IMPORTANT] -> Unless you don't want to build the 3D version, you need to build and install SDL_gpu first. Please refer to the build instructions at [SDL_gpu][3]. - -```sh -$ git clone https://github.com/sam-itt/sofis -$ cd sofis -$ git submodule update --init --recursive -$ cd sdl-pcf -$ autoreconf -i -$ ./configure --with-texture=sdl_gpu -``` - -Here we just need configure to generate a header for sdl_gpu to be usable. -Do *not* type make to build sdl_pcf at this stage. Continue with: - -```sh -$ cd .. -$ wget https://github.com/sam-itt/fg-roam/archive/media.tar.gz -$ tar -xf media.tar.gz --strip-components=1 -C fg-roam/ -``` - -If you are building for/on the Raspberry Pi, create a `switches.local` with the following content: - -``` -USE_GLES=1 -NO_PRELOAD=1 -TINY_TEXTURES=1 -GL_LIB=brcmGLESv2 -BNO080_DEV=\"/dev/i2c-0\" -``` - -If you are building for another platform adjust settings as needed by creating a `switches.local` -file to override settings presents in `switches.defaults`. We building on a PC defaults settings should -be fine. - -Then, proceed with the build: -```sh -$ make -``` - -## Running - -You can then run the self-contained demo with: - -```sh -$ ./sofis --fgtape -``` - -SoFIS comes with pre-recorded flight data of a circuit around LFLG (Grenoble, -France). - -Please note that the first run will be slower to start than others. SoFIS will -download content from FlightGear's mirrors for the synthetic vision and from -OSM + OpenAIP for the moving map. This download feature has been baked in for -convenience during testing/development. It will be disabled on "release" builds -that will rely only on pre-loaded data. - -You can zoom in/out the minimap using + and - keys on the keypad and move the -minimap itself using arrow keys. Press space to toggle the synthetic vision. - -## Using tiles from OpenAIP - -The map can display tiles from openaip. To enable this feature, you need to obtain -a (free) API key from [OpenAIP][10]. Simply create an account there and you'll be able -to get a key from your profile page. - -Then edit the `resources/maps/openaip/map.conf` file and replace YOUR-API-KEY with your key -in the following line: - -``` -src: https://api.tiles.openaip.net/api/data/openaip/%LEVEL%/%TILE_X%/%TILE_Y%.png?apiKey=YOUR-API-KEY -``` - -## Getting data from FlightGear - -SoFIS can be fed data over the network by FlightGear. You'll need to setup your -FlightGear install by copying `fg-io/flightgear-connector/basic_proto.xml` into -`$FG_ROOT/Protocol` on the FlightGear host. Once done, you can start SoFIS which -will tell you what to do: - -```sh -$ ./sofis --fgremote -[...] -Waiting for first packet from FlightGear -Be sure to: -1. have basic_proto.xml in $FG_ROOT/Protocol -2. Run FlightGear(fgfs) with --generic=socket,out,5,LOCAL_IP,6789,udp,basic_proto -Be sure to replace LOCAL_IP with the IP of the local machine, one of: - wlan0 IP Address 192.168.1.41 -``` - -> [!WARNING] -> Startup times on the Raspberry Pi can be *very* long, especillay with -> big 3d tiles. In my tests running the [ksfo-loop][4] on a remote computer and -> SoFIS in fgremote mode lead to arround *10 minutes of wall-clock* loading time -> (downloading+loading the btg). If SoFIS says "Loading btg:" it's not stuck, it -> is loading. - -## Getting data from Stratux - -Stratux support is is very basic and uses only the GPS and AHRS values reported -by the device. SoFIS currently currently uses the json protocol. GDL 90 support -will come later. - -You need to first connect the device you'll be running SoFIS to Startux over -wifi, and the you can launch SoFIS as follows: - -```sh -$ ./sofis --stratux -``` - -## Getting data from sensors - -SoFIS is still in early stages and currently doesn't have support for many -sensors. Your patches/pull requests are very welcome! - -Currently, these sensors are supported: - -|Kind | Device | State | -|-------------|-------------|---------------| -|GPS | gpsd | OK | -|AHRS | BNO080 | OK | - -### Position - -SoFIS needs [gpsd][5] to be properly configured and running. -Please refer to gpsd documentation on how to do that. Once you have gpsd -correctly outputing data from your GPS receiver, you can proceed with the next -steps. - -### Atittude / Heading - -SoFIS currently supports the BNO080 from Bosch/Hillcrest. This unit does -onboard sensor fusion (gyros, accelerometers and magnetometer) and outputs the -resulting orientation quaternion over i2c. - -If you are running on a Raspberry Pi, and using onboard i2c, you'll need to -modify your `/boot/config.txt` to get it to work. The Pi has a well-known -hardware bug that make clock stretching impossible. This is easily fixed by -setting the clock rate to a value that is acceptable to both the BNO080 and -the Pi: - -``` -dtparam=i2c_arm=on -dtparam=i2c_arm_baudrate=400000 -``` -SoFIS expects the IMU on `/dev/i2c-1` (default) or `/dev/i2c-0` (rpi). This -value can be changed in `switches.local` - -### Command line - -Run SoFIS with the following command line: -```sh -$ ./sofis --sensors -``` - -## Running on the Raspberry Pi (1/Zero) - -SoFIS has been tested on the Raspberry Pi 1 model B+: - - -It can surely work on later models, this is just untested due to the lack of -hardware. Your patches are welcome to fix any build issues on these platforms. - -SoFIS currently needs a 128/128 MB memory split which makes Raspbian really -slow. A Gentoo install is far more usable as it uses around 16MB of RAM at -logon. Here is a [link][6] to a bootable sd-card image that already have the -dependencies built in. - -### Building the SD Card - -Your SD Card must be at least 8GB for this image be written as-is. - -*WARNING* The following instructions *can* break your system if done improperly. -Be sure of the device you are writting to: A mistake here means a wiped hard -drive. You have been warned. - -We are going to assume that your sd-card is `/dev/mmcblkX`. Note that we are not -using partitions, but the whole device. - -```sh -$ wget https://github.com/sam-itt/gentoo-pie/releases/download/0.0.1/sdcard-gentoo.img.xz -$ wget https://github.com/sam-itt/gentoo-pie/releases/download/0.0.1/sdcard-gentoo.img.sha1 -$ sha1sum -c sdcard-gentoo.img.xz.sha1 -sdcard-gentoo.img.xz: OK -# xzcat sdcard-gentoo.img.xz > /dev/mmcblkX && sync -``` - -You can now put the card in your Pi and boot. Login/passwords are: - -* pi/pi -* root/pi - -Continue through the steps at [Building](#building) - -### Wiring - -| BNO080 | RPI | -|-------------|--------------| -| VCC (3.3V) | #1 - 3.3V | -| GND | #6 - GND | -| SDA | #8 - SDA0 | -| SCL | #9 - SCL0 | - -![rpi-bno080][8] - -## Running on an Orange Pi - -SoFIS has been reported by users to run on the Orange Pi. - -### Alternative minimal OS RTOS installation - -Using Armbian: - -Download the "Armbian 25.2.x bookworm Minimal" from [11]: -* Launch and setup the installation following Armbian's instructions. -* Install additional packages required for building and the "glu" -```sh -$ sudo apt install mesa-utils libgl1-mesa-dev libglu1-mesa-dev automake autoconf libtool -``` -* Follow the identical build steps above - -Once complete, SoFIS will run full screen. - -## Contributing - -SoFIS is still in very early stages of development. If you are willing to help -with the project, please have a look at the issues and the `TODO` file at the -root of the project (if there is any) to avoid duplicate work and see where -we are currently going. - -If you found a bug that you've fixed, don't hesitate to send patches or pull -requests. - -If you want to improve a feature, add something or do more in-depth work, please -get in touch first by opening a new github issue. - -[1]: https://github.com/sam-itt/sofis/blob/media/sofis-demo-480p.gif?raw=true -[2]: https://github.com/sam-itt/sofis/blob/media/sofis-rpi-b.png?raw=true -[3]: https://github.com/grimfang4/sdl-gpu -[4]: https://wiki.flightgear.org/Suggested_Prerecorded_Flights -[5]: https://gpsd.io/ -[6]: https://github.com/sam-itt/gentoo-pie/releases/download/0.0.1/sdcard-gentoo.img.xz -[7]: http://stratux.me/ -[8]: https://github.com/sam-itt/sofis/blob/media/sofis-bno080-rpi.png?raw=true -[9]: https://github.com/sam-itt/sofis/blob/media/sofis-direct-to.gif?raw=true -[10]: https://www.openaip.net/ -[11]: https://www.armbian.com/orangepi-5/ diff --git a/TerminusTTF-4.47.0.ttf b/TerminusTTF-4.47.0.ttf deleted file mode 100644 index d302264..0000000 Binary files a/TerminusTTF-4.47.0.ttf and /dev/null differ diff --git a/airspeed-indicator.c b/airspeed-indicator.c deleted file mode 100644 index 5da0df4..0000000 --- a/airspeed-indicator.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include - -#include "SDL_pcf.h" - -#include "airspeed-indicator.h" -#include "resource-manager.h" -#include "sdl-colors.h" -#include "misc.h" - -static BaseGaugeOps airspeed_indicator_ops = { - .render = (RenderFunc)NULL, - .update_state = (StateUpdateFunc)NULL, - .dispose = (DisposeFunc)NULL -}; - - -AirspeedIndicator *airspeed_indicator_new(speed_t v_so, speed_t v_s1, speed_t v_fe, speed_t v_no, speed_t v_ne) -{ - AirspeedIndicator *self; - - self = calloc(1, sizeof(AirspeedIndicator)); - if(self){ - if(!airspeed_indicator_init(self, v_so, v_s1, v_fe, v_no, v_ne)){ - return base_gauge_free(BASE_GAUGE(self)); - } - } - return self; -} - - -AirspeedIndicator *airspeed_indicator_init(AirspeedIndicator *self, speed_t v_so, speed_t v_s1, speed_t v_fe, speed_t v_no, speed_t v_ne) -{ - PCF_Font *fnt; - DigitBarrel *db; - - base_gauge_init(BASE_GAUGE(self), &airspeed_indicator_ops, 68, 240+20); - - fnt = resource_manager_get_font(TERMINUS_18); - db = digit_barrel_new(fnt, 0, 9.999, 1); - self->tape = tape_gauge_new( - 68, 240, - (LadderPageDescriptor*)airspeed_page_descriptor_new( - 68, 240, - roundf(240*0.0835f), - roundf(0.55f*(68*0.20f)), roundf(68*0.20f), - v_so, v_s1, v_fe, v_no, v_ne - ), - AlignRight, -12, 3, - -1, db, - -2, db, - -2, db - ); - base_gauge_add_child(BASE_GAUGE(self), BASE_GAUGE(self->tape), 0, 0); - - self->txt = text_gauge_new(NULL, true, 68, 21); - self->txt->alignment = HALIGN_CENTER | VALIGN_MIDDLE; - text_gauge_set_static_font(self->txt, - resource_manager_get_static_font(TERMINUS_12, - &SDL_WHITE, - 2, "TASKT-", PCF_DIGITS - ) - ); - base_gauge_add_child(BASE_GAUGE(self), BASE_GAUGE(self->txt), - 0, - base_gauge_h(BASE_GAUGE(self)) - 20 - 1 - ); - text_gauge_set_color(self->txt, SDL_BLACK, BACKGROUND_COLOR); - - airspeed_indicator_set_value(self, 0.0); - return self; -} - -bool airspeed_indicator_set_value(AirspeedIndicator *self, float value) -{ - float cad; /*Current air density, must be in kg/m3 (same unit as RHO_0)*/ - - cad = RHO_0; /*Placeholder, should be reported by a sensor*/ - - self->tas = round(value * sqrt(RHO_0/cad)); - text_gauge_set_value_formatn(self->txt, - 9, /*TAS XXXKT*/ - "TAS %03dKT", self->tas - ); - - tape_gauge_set_value(self->tape, value, true); - - return true; -} diff --git a/airspeed-indicator.h b/airspeed-indicator.h deleted file mode 100644 index 5c02dee..0000000 --- a/airspeed-indicator.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef AIRSPEED_INDICATOR_H -#define AIRSPEED_INDICATOR_H - -#include "base-gauge.h" -#include "tape-gauge.h" -#include "text-gauge.h" -#include "airspeed-page-descriptor.h" - -#define RHO_0 1.225 /* kg/m3, Sea level ISA */ - -typedef struct{ - BaseGauge super; - - TapeGauge *tape; - TextGauge *txt; - - int tas; -}AirspeedIndicator; - - -AirspeedIndicator *airspeed_indicator_new(speed_t v_so, speed_t v_s1,speed_t v_fe,speed_t v_no,speed_t v_ne); -AirspeedIndicator *airspeed_indicator_init(AirspeedIndicator *self, speed_t v_so, speed_t v_s1,speed_t v_fe,speed_t v_no,speed_t v_ne); - -bool airspeed_indicator_set_value(AirspeedIndicator *self, float value); -#endif /* AIRSPEED_INDICATOR_H */ diff --git a/airspeed-page-descriptor.c b/airspeed-page-descriptor.c deleted file mode 100644 index 3fa4683..0000000 --- a/airspeed-page-descriptor.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include - - -#include "airspeed-page-descriptor.h" -#include "generic-layer.h" -#include "ladder-page.h" -#include "sdl-colors.h" -#include "vertical-strip.h" - - - -LadderPage *airspeed_ladder_page_init(LadderPage *self); -static void airspeed_ladder_page_draw_arc(LadderPage *self, float start, float end, uintf8_t width, Uint32 color); -static void airspeed_ladder_page_draw_arcs(LadderPage *self); - - -AirspeedPageDescriptor *airspeed_page_descriptor_new(int page_w, int page_h_min, uintf8_t unit_px_sz, - int small_step_width, int big_step_width, - speed_t v_so, speed_t v_s1, speed_t v_fe, - speed_t v_no, speed_t v_ne) -{ - AirspeedPageDescriptor *self; - int pattern_h; - - self = calloc(1, sizeof(AirspeedPageDescriptor)); - if(!self) - return NULL; - - self->v_so = v_so; - self->v_s1 = v_s1; - self->v_fe = v_fe; - self->v_no = v_no; - self->v_ne = v_ne; - - vruler_page_descriptor_init( - VRULER_PAGE_DESCRIPTOR(self), - page_w, page_h_min, - unit_px_sz, - small_step_width, big_step_width, - 10, 5, - BOTTUM_UP, airspeed_ladder_page_init - ); - - return self; -} - - -LadderPage *airspeed_ladder_page_init(LadderPage *self) -{ - vruler_ladder_page_init(self, LocationRight); - - airspeed_ladder_page_draw_arcs(self); - generic_layer_build_texture(GENERIC_LAYER(self)); - - return self; -} - -void airspeed_ladder_page_draw_arcs(LadderPage *self) -{ - AirspeedPageDescriptor *descriptor; - float green_start, green_end; - float yellow_start, yellow_end; - float white_start, white_end; - - descriptor = (AirspeedPageDescriptor *)self->descriptor; - green_start = (descriptor->v_s1); - green_end = (descriptor->v_no); - yellow_start = (descriptor->v_no); - yellow_end = (descriptor->v_ne); - white_start = (descriptor->v_so); - white_end = (descriptor->v_fe); - - /*Green arc*/ -// printf("Green arc from %d kts to %d kts\n",descriptor->v_s1, descriptor->v_no); - airspeed_ladder_page_draw_arc(self, descriptor->v_s1, descriptor->v_no, 4, SDL_UGREEN(GENERIC_LAYER(self)->canvas)); - /*Yellow*/ - airspeed_ladder_page_draw_arc(self, descriptor->v_no, descriptor->v_ne, 4, SDL_UYELLOW(GENERIC_LAYER(self)->canvas)); - /*White last, over any existing*/ - airspeed_ladder_page_draw_arc(self, descriptor->v_so, descriptor->v_fe, 2, SDL_UGREY(GENERIC_LAYER(self)->canvas)); - - /*VNE*/ - airspeed_ladder_page_draw_arc(self, descriptor->v_ne, descriptor->v_ne+2, 4, SDL_URED(GENERIC_LAYER(self)->canvas)); -} - - -static void airspeed_ladder_page_draw_arc(LadderPage *self, float start, float end, uintf8_t width, Uint32 color) -{ - float istart, iend; - float ystart, yend; - int firsty, lasty; - Uint32 *pixels; - SDL_Surface *surface; - int x; - Uint32 white; - - if(interval_intersect(start, end, VERTICAL_STRIP(self)->start, VERTICAL_STRIP(self)->end, &istart, &iend)){ - surface = GENERIC_LAYER(self)->canvas; - white = SDL_UWHITE(surface); - - ystart = ladder_page_resolve_value(self, istart); - yend = ladder_page_resolve_value(self, iend); - - firsty = (ystart < yend) ? ystart : yend; - lasty = (yend > ystart) ? yend : ystart; - - if(firsty < 0) firsty = 0; - if(lasty > (surface->h-1)) lasty = surface->h-1; -/* - printf("Intersection between arc from %f to %f and current page from %f to %f is %f,%f and will be starting at Y:%d to Y:%d\n", - start, end, VERTICAL_STRIP(self)->start, VERTICAL_STRIP(self)->end, - istart, iend, - firsty, lasty - );*/ - - SDL_LockSurface(surface); - pixels = surface->pixels; - for(int i = firsty; i <= lasty; i++){ - x = ((surface->w-1)-1) - (width-1); /*second -1 to avoid eating the border*/ - for(int j = x; j < surface->w; j++){ - Uint32 idx = i * surface->w + j; - if(pixels[idx] != white) /*Avoid eating the marks*/ - pixels[idx] = color; - } - } - SDL_UnlockSurface(surface); - }else{/* - printf("No intersection between arc from %f to %f and current page from %f to %f\n", - start, end, VERTICAL_STRIP(self)->start, VERTICAL_STRIP(self)->end - );*/ - - } -} - diff --git a/airspeed-page-descriptor.h b/airspeed-page-descriptor.h deleted file mode 100644 index 54570a2..0000000 --- a/airspeed-page-descriptor.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef AIRSPEED_PAGE_DESCRIPTOR_H -#define AIRSPEED_PAGE_DESCRIPTOR_H - -#include "vruler-page-descriptor.h" - -/* uintf8_t: Good for 250 knots. Real units show 240 kts. - * change type (i.e uint_fast_16_t) for higher speeds - * */ -typedef uint_fast8_t speed_t; - - -typedef struct{ - VRulerPageDescriptor super; - - speed_t v_so; /*white arc begin*/ - speed_t v_s1; /*green arc begin*/ - speed_t v_fe; /*white arc end*/ - speed_t v_no; /*green arc end, yellow arc begin*/ - speed_t v_ne; /*green arc end, yellow arc end, red line*/ -}AirspeedPageDescriptor; - - -AirspeedPageDescriptor *airspeed_page_descriptor_new(int page_w, int page_h_min, uintf8_t unit_px_sz, - int small_step_width, int big_step_width, - speed_t v_so, speed_t v_s1, speed_t v_fe, - speed_t v_no, speed_t v_ne); - - -#endif /* AIRSPEED_PAGE_DESCRIPTOR_H */ diff --git a/alt-group.c b/alt-group.c deleted file mode 100644 index 2e85f6c..0000000 --- a/alt-group.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include - -#include "alt-group.h" -#include "base-gauge.h" -#include "resource-manager.h" -#include "sdl-colors.h" -#include "SDL_pcf.h" -#include "vertical-speed-indicator.h" -#include "res-dirs.h" - -static BaseGaugeOps alt_group_ops = { - .render = (RenderFunc)NULL, - .update_state = (StateUpdateFunc)NULL, - .dispose = (DisposeFunc)NULL -}; - - -AltGroup *alt_group_new(void) -{ - AltGroup *self; - self = calloc(1, sizeof(AltGroup)); - if(self){ - if(!alt_group_init(self)){ - return base_gauge_free(BASE_GAUGE(self)); - } - } - return self; -} - -AltGroup *alt_group_init(AltGroup *self) -{ - self->altimeter = alt_indicator_new(); - self->vsi = vertical_speed_indicator_new(29, 191, TERMINUS_16); - if(!self->vsi || !self->altimeter) - goto bail; - - /* TODO: Move me as first operation to ensure that Ops are always - * set when we return NULL so that base_gauge_dispose (called by - * base_gauge_free) can properly dispose any gauge-allocated resources*/ - base_gauge_init( - BASE_GAUGE(self), - &alt_group_ops, - base_gauge_w(BASE_GAUGE(self->altimeter)) + base_gauge_w(BASE_GAUGE(self->vsi)), - (base_gauge_h(BASE_GAUGE(self->vsi)) > base_gauge_h(BASE_GAUGE(self->altimeter))) ? - base_gauge_h(BASE_GAUGE(self->vsi)) : - base_gauge_h(BASE_GAUGE(self->altimeter)) - ); - - base_gauge_add_child(BASE_GAUGE(self), BASE_GAUGE(self->altimeter), 0, 0); - base_gauge_add_child(BASE_GAUGE(self), BASE_GAUGE(self->vsi), - base_gauge_w(BASE_GAUGE(self->altimeter)), - base_gauge_h(BASE_GAUGE(self->altimeter))/2 - base_gauge_h(BASE_GAUGE(self->vsi))/2 - ); - return self; - -bail: - if(self->vsi) free(self->vsi); - if(self->altimeter) free(self->altimeter); - return NULL; -} - -void alt_group_set_altitude(AltGroup *self, float value) -{ - alt_indicator_set_value(self->altimeter, value, true); -} - -void alt_group_set_vertical_speed(AltGroup *self, float value) -{ - vertical_speed_indicator_set_value(self->vsi, value, true); -} - -void alt_group_set_values(AltGroup *self, float alt, float vs) -{ - alt_group_set_altitude(self, alt); - alt_group_set_vertical_speed(self, vs); -} - diff --git a/alt-group.h b/alt-group.h deleted file mode 100644 index 7791d88..0000000 --- a/alt-group.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef ALT_GROUP_H -#define ALT_GROUP_H - -#include "base-gauge.h" -#include "alt-indicator.h" -#include "vertical-speed-indicator.h" - -typedef struct{ - BaseGauge super; - - AltIndicator *altimeter; - VerticalSpeedIndicator *vsi; -}AltGroup; - -AltGroup *alt_group_new(void); -AltGroup *alt_group_init(AltGroup *self); - -void alt_group_set_altitude(AltGroup *self, float value); -void alt_group_set_vertical_speed(AltGroup *self, float value); -void alt_group_set_values(AltGroup *self, float alt, float vs); - -#endif /* ALT_GROUP_H */ diff --git a/alt-indicator.c b/alt-indicator.c deleted file mode 100644 index 81ef360..0000000 --- a/alt-indicator.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include - -#include "alt-indicator.h" - -#include "altitude-page-descriptor.h" -#include "resource-manager.h" -#include "sdl-colors.h" -#include "misc.h" -#include "tape-gauge.h" - -static BaseGaugeOps alt_indicator_ops = { - .render = (RenderFunc)NULL, - .update_state = (StateUpdateFunc)NULL, - .dispose = (DisposeFunc)NULL -}; - - -AltIndicator *alt_indicator_new(void) -{ - AltIndicator *self; - self = calloc(1, sizeof(AltIndicator)); - if(self){ - if(!alt_indicator_init(self)){ - return base_gauge_free(BASE_GAUGE(self)); - } - } - return self; -} - -AltIndicator *alt_indicator_init(AltIndicator *self) -{ - PCF_Font *fnt; - - base_gauge_init(BASE_GAUGE(self), &alt_indicator_ops, 68, 240+20); - - /*TODO: Change size to size - 20, when size becomes a parameter ! - * temporary fixed in the rendering function by drawing the ladder first - * and then drawing on it - * */ - fnt = resource_manager_get_font(TERMINUS_18); - DigitBarrel *db = digit_barrel_new(fnt, 0, 9.999, 1); - DigitBarrel *db2 = digit_barrel_new(fnt, 0, 99, 10); - self->tape = tape_gauge_new( - 68, 240, - (LadderPageDescriptor*)altitude_page_descriptor_new( - 68, 240, - roundf(240*0.032f), - roundf(0.55f*(68*0.15f)), roundf(68*0.15f) - ), - AlignRight, 0, 4, - -1, db2, - -2, db, - -2, db, - -2, db - ); - base_gauge_add_child(BASE_GAUGE(self), BASE_GAUGE(self->tape), 0, 19); - - self->talt_txt = text_gauge_new(NULL, true, 68, 20); - self->talt_txt->alignment = HALIGN_CENTER | VALIGN_MIDDLE; - text_gauge_set_static_font(self->talt_txt, - resource_manager_get_static_font(TERMINUS_16, - &SDL_WHITE, - 1, PCF_DIGITS - ) - ); - base_gauge_add_child(BASE_GAUGE(self), BASE_GAUGE(self->talt_txt), 0, 0); - - text_gauge_set_color(self->talt_txt, SDL_BLACK, BACKGROUND_COLOR); - text_gauge_set_value(self->talt_txt, "0"); - - self->qnh_txt = text_gauge_new(NULL, true, 68, 22); - self->qnh_txt->alignment = HALIGN_CENTER | VALIGN_MIDDLE; - text_gauge_set_static_font(self->qnh_txt, - resource_manager_get_static_font(TERMINUS_16, - &SDL_WHITE, - 1, PCF_DIGITS - ) - ); - base_gauge_add_child(BASE_GAUGE(self), BASE_GAUGE(self->qnh_txt), - 0, - base_gauge_h(BASE_GAUGE(self)) - 20 - 2 - ); - - text_gauge_set_color(self->qnh_txt, SDL_BLACK, BACKGROUND_COLOR); - alt_indicator_set_alt_src(self, ALT_SRC_GPS); - - return self; -} - -bool alt_indicator_set_value(AltIndicator *self, float value, bool animated) -{ - return tape_gauge_set_value(self->tape, value, animated); -} - -/*HPa*/ -void alt_indicator_set_qnh(AltIndicator *self, float value) -{ - int ivalue; - - ivalue = round(value); - - if(self->qnh != ivalue){ - self->qnh = ivalue; - text_gauge_set_value_formatn(self->qnh_txt, - 4, /*4 digits*/ - "%04d", self->qnh - ); - } -} - -void alt_indicator_set_alt_src(AltIndicator *self, AltSource source) -{ - if(source == ALT_SRC_GPS){ - text_gauge_set_font(self->qnh_txt, - resource_manager_get_font(TERMINUS_16) - ); - text_gauge_set_color(self->qnh_txt, SDL_RED, TEXT_COLOR); - text_gauge_set_value(self->qnh_txt, "GPS"); - }else{ - text_gauge_set_static_font(self->qnh_txt, - resource_manager_get_static_font(TERMINUS_16, - &SDL_WHITE, - 1, PCF_DIGITS - ) - ); - alt_indicator_set_qnh(self, 1013.25); - } -} diff --git a/alt-indicator.h b/alt-indicator.h deleted file mode 100644 index 1f5b593..0000000 --- a/alt-indicator.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef ALT_INDICATOR_H -#define ALT_INDICATOR_H - -#include "base-gauge.h" -#include "generic-layer.h" -#include "tape-gauge.h" -#include "text-gauge.h" - -typedef enum {ALT_SRC_GPS,ALT_SRC_BARO} AltSource; - -typedef struct{ - BaseGauge super; - - TapeGauge *tape; - TextGauge *talt_txt; /*Target altitude*/ - TextGauge *qnh_txt; - - AltSource src; - int qnh; - int target_alt; -}AltIndicator; - -AltIndicator *alt_indicator_new(void); -AltIndicator *alt_indicator_init(AltIndicator *self); - -bool alt_indicator_set_value(AltIndicator *self, float value, bool animated); -void alt_indicator_set_qnh(AltIndicator *self, float value); - -void alt_indicator_set_alt_src(AltIndicator *self, AltSource source); -#endif /* ALT_INDICATOR_H */ diff --git a/altitude-page-descriptor.c b/altitude-page-descriptor.c deleted file mode 100644 index 5800f40..0000000 --- a/altitude-page-descriptor.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2026 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include - -#include "altitude-page-descriptor.h" -#include "misc.h" - - -AltitudePageDescriptor *altitude_page_descriptor_new(int page_w, int page_h_min, - uintf8_t unit_px_sz, int small_step_width, - int big_step_width) -{ - AltitudePageDescriptor *self; - int pattern_h; - - self = calloc(1, sizeof(AltitudePageDescriptor)); - if(!self) - return NULL; - - vruler_page_descriptor_init( - VRULER_PAGE_DESCRIPTOR(self), - page_w, page_h_min, - unit_px_sz, - small_step_width, big_step_width, - 100, 20, - BOTTUM_UP, altitude_ladder_page_init); - - return self; -} - - -LadderPage *altitude_ladder_page_init(LadderPage *self) -{ - vruler_ladder_page_init(self, LocationLeft); - generic_layer_build_texture(GENERIC_LAYER(self)); - - return self; -} - diff --git a/altitude-page-descriptor.h b/altitude-page-descriptor.h deleted file mode 100644 index a0e24cf..0000000 --- a/altitude-page-descriptor.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2026 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef ALTITUDE_PAGE_DESCRIPTOR_H -#define ALTITUDE_PAGE_DESCRIPTOR_H -#include - -#include "vruler-page-descriptor.h" - -typedef struct{ - VRulerPageDescriptor super; -}AltitudePageDescriptor; - -AltitudePageDescriptor *altitude_page_descriptor_new(int page_w, int page_h_min, - uintf8_t unit_px_sz, int small_step_width, - int big_step_width); -LadderPage *altitude_ladder_page_init(LadderPage *self); - - -#endif /* ALTITUDE_PAGE_DESCRIPTOR_H */ diff --git a/attitude-indicator.c b/attitude-indicator.c deleted file mode 100644 index c95db8d..0000000 --- a/attitude-indicator.c +++ /dev/null @@ -1,817 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include - -#include -#include - -#include "SDL_pcf.h" - -#include "attitude-indicator.h" -#include "base-animation.h" -#include "base-gauge.h" -#include "generic-layer.h" -#include "misc.h" -#include "resource-manager.h" -#include "roll-slip-gauge.h" -#include "sdl-colors.h" -#include "res-dirs.h" - -#define sign(x) (((x) > 0) - ((x) < 0)) - -static void attitude_indicator_render(AttitudeIndicator *self, Uint32 dt, RenderContext *ctx); -static void attitude_indicator_update_state(AttitudeIndicator *self, Uint32 dt); -static void *attitude_indicator_dispose(AttitudeIndicator *self); -static BaseGaugeOps attitude_indicator_ops = { - .render = (RenderFunc)attitude_indicator_render, - .update_state = (StateUpdateFunc)attitude_indicator_update_state, - .dispose = (DisposeFunc)attitude_indicator_dispose -}; - -static SDL_Surface *attitude_indicator_get_etched_ball(AttitudeIndicator *self); -static SDL_Surface *attitude_indicator_draw_ruler(AttitudeIndicator *self, int size, int ppm, PCF_Font *font, SDL_Color *col); - -AttitudeIndicator *attitude_indicator_new(int width, int height) -{ - - AttitudeIndicator *self; - self = calloc(1, sizeof(AttitudeIndicator)); - if(self){ - if(!attitude_indicator_init(self, width, height)){ - return base_gauge_free(BASE_GAUGE(self)); - } - } - return self; -} - - -AttitudeIndicator *attitude_indicator_init(AttitudeIndicator *self, int width, int height) -{ - base_gauge_init(BASE_GAUGE(self), &attitude_indicator_ops, width, height); - - self->common_center.x = round((base_gauge_w(BASE_GAUGE(self)))/2.0); -#if 1 - self->common_center.y = round(base_gauge_h(BASE_GAUGE(self))*0.4); -#else - self->common_center.y = round(base_gauge_h(BASE_GAUGE(self))/2.0); -#endif - self->size = 2; /*In tens of degrees, here 20deg (+/-)*/ - - /*TODO: Failure*/ - generic_layer_init_from_file(&self->markers[MARKER_LEFT], IMG_DIR"/left-marker.png"); - generic_layer_init_from_file(&self->markers[MARKER_RIGHT], IMG_DIR"/right-marker.png"); - generic_layer_init_from_file(&self->markers[MARKER_CENTER], IMG_DIR"/center-marker.png"); - for(int i = 0; i < 3; i++) - generic_layer_build_texture(&self->markers[i]); - - self->rollslip = roll_slip_gauge_new(); - - self->locations[MARKER_LEFT] = (SDL_Rect){ - /*The left marker has its arrow pointing right and the arrow X is at marker->w-1*/ - self->common_center.x - 78 - (generic_layer_w(&self->markers[0])-1), - self->common_center.y - round(generic_layer_h(&self->markers[0])/2.0) /*+1*/, - generic_layer_w(&self->markers[MARKER_LEFT]), generic_layer_h(&self->markers[MARKER_LEFT]) - }; - self->locations[MARKER_RIGHT] = (SDL_Rect){ - self->common_center.x + 78, - self->locations[MARKER_LEFT].y, - generic_layer_w(&self->markers[MARKER_RIGHT]), generic_layer_h(&self->markers[MARKER_RIGHT]) - }; - self->locations[MARKER_CENTER] = (SDL_Rect){ - self->common_center.x - round((generic_layer_w(&self->markers[2])-1)/2.0), - self->common_center.y /*+ 1*/, - generic_layer_w(&self->markers[MARKER_CENTER]), generic_layer_h(&self->markers[MARKER_CENTER]) - }; - - self->locations[ROLL_SLIP] = (SDL_Rect){ - self->common_center.x - round((base_gauge_h(BASE_GAUGE(self->rollslip))-1)/2.0), - 7, - 0,0 - }; - base_gauge_add_child(BASE_GAUGE(self), BASE_GAUGE(self->rollslip), - self->locations[ROLL_SLIP].x, - self->locations[ROLL_SLIP].y - ); - - attitude_indicator_get_etched_ball(self); -#if ENABLE_3D - /* Verticaly 7 pixels -> 1 degree, 2.5 degrees = 17 pixels - * Horizontaly 8 pixels -> 1 degree. - * Values found using screenshots and dividing - * pixels by degrees. TODO: Find out how to - * properly compute those values - * */ - - self->pitch_ruler = attitude_indicator_draw_ruler(self, - self->size, 17, - resource_manager_get_font(TERMINUS_12), - &(SDL_Color){0,255,0} - ); - SDL_SetSurfaceBlendMode(self->pitch_ruler, SDL_BLENDMODE_NONE); - - /*TODO: Generate*/ - self->horizon_src = IMG_Load(IMG_DIR"/horizon-grads-scaled.png"); - if(!self->horizon_src) - return NULL; - SDL_SetSurfaceBlendMode(self->horizon_src, SDL_BLENDMODE_NONE); - - self->diagonal = sqrt( - base_gauge_w(BASE_GAUGE(self))*base_gauge_w(BASE_GAUGE(self)) - + base_gauge_h(BASE_GAUGE(self))*base_gauge_h(BASE_GAUGE(self)) - ); - generic_layer_init(&self->phh_overlay, self->diagonal, self->pitch_ruler->h); -#endif - -#if !USE_SDL_GPU - self->state.rbuffer = SDL_CreateRGBSurfaceWithFormat(0, width*2, height*2, 32, SDL_PIXELFORMAT_RGBA32); - self->renderer = SDL_CreateSoftwareRenderer(self->state.rbuffer); - self->ball_texture = SDL_CreateTextureFromSurface(self->renderer, self->etched_ball.canvas); -#endif - - return self; -} - -static bool attitude_indicator_init_animations(AttitudeIndicator *self) -{ - /* We need to pre-create animations as there can/will be two - * of them and we need to know which one is which*/ - BaseAnimation *animation; - bool rv; - - animation = base_animation_new(TYPE_FLOAT, 2, - &self->roll, - &SFV_GAUGE(self->rollslip)->value - ); - if(!animation) - return false; - rv = base_gauge_add_animation(BASE_GAUGE(self), animation); - if(!rv) - return false; - - animation = base_animation_new(TYPE_FLOAT, 1, &self->pitch); - if(!animation) - return false; - rv = base_gauge_add_animation(BASE_GAUGE(self), animation); - - return rv; -} - -static void *attitude_indicator_dispose(AttitudeIndicator *self) -{ - for(int i = 0; i < 3; i++){ - generic_layer_dispose(&self->markers[i]); - } -#if !USE_SDL_GPU - if(self->state.rbuffer) - SDL_FreeSurface(self->state.rbuffer); - SDL_DestroyRenderer(self->renderer); -#endif - generic_layer_dispose(&self->etched_ball); -#if ENABLE_3D - if(self->horizon_src) - SDL_FreeSurface(self->horizon_src); - if(self->pitch_ruler) - SDL_FreeSurface(self->pitch_ruler); - generic_layer_dispose(&self->phh_overlay); -#endif - return self; -} - -bool attitude_indicator_set_roll(AttitudeIndicator *self, float value, bool animated) -{ - BaseAnimation *animation; - bool rv; - - animated = (self->mode == AI_MODE_3D) ? false : animated; - - if(animated){ - if(BASE_GAUGE(self)->nanimations == 0){ - rv = attitude_indicator_init_animations(self); - if(!rv) - goto fallback; - } - animation = BASE_GAUGE(self)->animations[AI_ROLL_ANIMATION]; - base_animation_start(animation, self->roll, value, DEFAULT_DURATION); - }else{ -fallback: - self->roll = value; - roll_slip_gauge_set_value(self->rollslip, value, false); - BASE_GAUGE(self)->dirty = true; - } - return true; - } - -bool attitude_indicator_set_pitch(AttitudeIndicator *self, float value, bool animated) -{ - BaseAnimation *animation; - bool rv; - - value = (value > self->size*10) ? self->size*10 + 5 : value; - value = (value < self->size*-10) ? self->size*-10 - 5: value; - - animated = (self->mode == AI_MODE_3D) ? false : animated; - -// printf("%s %p value: %f\n",__FUNCTION__, self, value); - if(animated){ - if(BASE_GAUGE(self)->nanimations == 0){ - rv = attitude_indicator_init_animations(self); - if(!rv) - goto fallback; - } - animation = BASE_GAUGE(self)->animations[AI_PITCH_ANIMATION]; - base_animation_start(animation, self->pitch, value, DEFAULT_DURATION); - }else{ -fallback: - if(value != self->pitch){ - self->pitch = value; - BASE_GAUGE(self)->dirty = true; - } - } - return true; -} - -bool attitude_indicator_set_heading(AttitudeIndicator *self, float value) -{ - bool rv; - - if(value > 360 || value < 0) return false; - - self->heading = value; - BASE_GAUGE(self)->dirty = true; - - return true; -} - - -Uint32 interpolate_color_p(const SDL_PixelFormat *format, Uint32 from, Uint32 to, float progress) -{ - Uint8 fr,fg,fb; - Uint8 tr,tg,tb; - Uint8 rv_r, rv_g, rv_b; - - SDL_GetRGB(from, format, &fr, &fg, &fb); - SDL_GetRGB(to, format, &tr, &tg, &tb); -// printf("Interpolate between (%d,%d,%d) and (%d,%d,%d), progress=%0.2f percent\n",fr,fg,fb,tr,tg,tb, progress*100); - -#if 1 - rv_r = fr + round((tr-fr)*progress); - rv_g = fg + round((tg-fg)*progress); - rv_b = fb + round((tb-fb)*progress); -#elif 0 - rv_r = round((1.0-progress) * fr + progress * tr + 0.5); - rv_g = round((1.0-progress) * fg + progress * tg + 0.5); - rv_b = round((1.0-progress) * fb + progress * tb + 0.5); -#endif - - return SDL_MapRGB(format, rv_r, rv_g, rv_b); -} - -float range_progress(float value, float start, float end) -{ - float rv; - float _v, _s, _e; - _v = value - start; - _e = end - start; - - rv = _v/_e; - -// printf("Progress=%0.2f value=%0.2f start=%0.2f, end=%0.2f\n",rv, value, start, end); - return rv; -} - -SDL_Surface *attitude_indicator_draw_ball(AttitudeIndicator *self) -{ - Uint32 *pixels; - SDL_Surface *surface; - int x, y, limit; - Uint32 white; - Uint32 sky,sky_down; - Uint32 earth; - - self->ball_window = (SDL_Rect){ - .x = 0, .y = 0, - .w = base_gauge_w(BASE_GAUGE(self)), - .h = base_gauge_h(BASE_GAUGE(self)) - }; - - self->ball_all = (SDL_Rect){ - .x = 0, .y = 0, - .w = self->ball_window.w*2, - .h = self->ball_window.h*2 - }; - - surface = SDL_CreateRGBSurfaceWithFormat(0, self->ball_all.w, self->ball_all.h, 32, SDL_PIXELFORMAT_RGBA32); - SDL_LockSurface(surface); - pixels = surface->pixels; - - white = SDL_UWHITE(surface); -// earth = SDL_MapRGB(surface->format, 0x46, 0x2b, 0x0c); -// earth = SDL_MapRGB(surface->format, 0x45, 0x2a, 0x06); -// earth = SDL_MapRGB(surface->format, 0x44, 0x28, 0x07); -// earth = SDL_MapRGB(surface->format, 0x3f, 0x28, 0x0a); - earth = SDL_MapRGB(surface->format, 0x58, 0x34, 0x0a); -// sky = SDL_MapRGB(surface->format, 0x13, 0x51, 0xd3); - sky = SDL_MapRGB(surface->format, 0x00, 0x50, 0xff); - sky_down = SDL_MapRGB(surface->format, 0x52, 0x6c, 0xd0); - - - - //limit = round(surface->h*0.4); /*40/60 split between sky and earth*/ - SDLExt_RectCenter(&self->ball_window, &self->ball_all); /*window x,y coordinates are now relative to "all" x,y*/ - limit = self->ball_window.y + round(self->ball_window.h*0.4); /*40/60 split between sky and earth*/ - - self->ball_horizon = limit; /*self->ball_horizon is in "all" units*/ - self->ball_center.y = limit; /*TODO: Merge these two center.y and limit*/ - self->ball_center.x = round(self->ball_all.w/2.0)-1; - - int first_gradient = round(limit * 0.25); /*First gradiant from the centerline to 25% up*/ - int first_gradiant_stop = limit - first_gradient; - Uint32 color; - - /*Draw the sky*/ - for(y = limit; y >= 0; y--){ - if(y > first_gradiant_stop){ - float progress; - progress = range_progress(y, limit, first_gradiant_stop); - - color = interpolate_color_p(surface->format, sky_down, sky, progress ); - }else{ - color = sky; -// exit(0); - } - for(int x = 0; x < surface->w; x++){ - pixels[y * surface->w + x] = color; - } - } - - /*Draw a white center line*/ - y = limit; - for(x = 0; x < surface->w; x++){ - pixels[y * surface->w + x] = white; - } - - /*Draw the earth*/ - int start = y +1; - for(y = start; y < surface->h; y++){ - for(int x = 0; x < surface->w; x++){ -// pixels[y * surface->w + x] = interpolate_color(surface->format, white, earth, y, start, surface->h-1); - pixels[y * surface->w + x] = earth; - } - } - SDL_UnlockSurface(surface); - - return surface; -} - -/** - * Draws a vertical pitch "ruler". - * - * Calling code must free the returned surface. - * Internal use only - * - * TODO: Replace this with GenericRuler - * - * @param self a AttitudeIndicator - * @param size The number of 10th graduations, both ways. A value of 2 means - * etches from 20 to -20 degrees. - * @param ppm Pixels per 2.5 etch. How much pixel a 2.5 degree interval - * (base etching) does take. - * @param font the PCF_Font used to draw the marks - */ -static SDL_Surface *attitude_indicator_draw_ruler(AttitudeIndicator *self, int size, int ppm, PCF_Font *font, SDL_Color *col) -{ - SDL_Surface *rv; - Uint32 *pixels; - int width, height; - int x, y; - int start_x, middle_x, end_x; - int middle_y; - -// int ppm = 9; /*17*/ /*pixels per mark*/ - int hfactor = (20/2.5)*ppm + 1; /*20 is the span between -10 to 10*/ - int yoffset = 10; - - /* Width: 57px wide for the 10s graduations plus 2x20 to allow space for the font*/ - width = 57+(2*20); - middle_x = (57-1)/2 + 19; - /* Height: hfactor px for +10 and -10 graduations by the size */ - height = hfactor*size + 20; - printf("max height: %d\n", height-1); //166 values from 0 to 165 - middle_y = ((hfactor*size)-1)/2.0 + yoffset; - - self->ruler_center.x = middle_x; - self->ruler_center.y = middle_y; - - rv = SDL_CreateRGBSurfaceWithFormat(0, width, height, 32, SDL_PIXELFORMAT_RGBA32); -// SDL_SetColorKey(rv, SDL_TRUE, SDL_UCKEY(rv)); -// SDL_FillRect(rv, NULL, SDL_UCKEY(rv)); - - - SDL_LockSurface(rv); - pixels = rv->pixels; - Uint32 color = SDL_MapRGB(rv->format, col->r, col->g, col->b); - Uint32 mcolor = SDL_URED(rv); - - int grad_level; - int grad_sizes[] = {57,11,25,11}; - - /*Go upwards*/ - grad_level = 0; - for(y = middle_y; y >= 0+yoffset; y--){ - if( (y-middle_y) % ppm == 0){ - start_x = middle_x - (grad_sizes[grad_level]-1)/2; - end_x = middle_x + (grad_sizes[grad_level]-1)/2; - - for( x = start_x; x <= end_x; x++){ - pixels[y * rv->w + x] = color; - } - pixels[y * rv->w + middle_x] = mcolor; - - grad_level = (grad_level < 3) ? grad_level + 1 : 0; - } - } - /*Go downwards*/ - grad_level = 0; - for(y = middle_y; y < rv->h-yoffset; y++){ - if( (y-middle_y) % ppm == 0){ - start_x = middle_x - (grad_sizes[grad_level]-1)/2; - end_x = middle_x + (grad_sizes[grad_level]-1)/2; - - for( x = start_x; x <= end_x; x++){ - pixels[y * rv->w + x] = color; - } - pixels[y * rv->w + middle_x] = mcolor; - - grad_level = (grad_level < 3) ? grad_level + 1 : 0; - } - } - SDL_UnlockSurface(rv); - - int current_grad; - Uint32 tcol; /*text color*/ - - tcol = SDL_MapRGB(rv->format, col->r, col->g, col->b); - - /*Go upwards*/ - current_grad = 0; - for(y = middle_y; y >= 0+yoffset; y--){ - if((y-middle_y) % (4*ppm) == 0){ // 10 graduation - if(current_grad > 0){ - PCF_FontWriteNumberAt(font, - ¤t_grad, TypeInt, 2, - tcol, false, rv, - middle_x - (57-1)/2 - 4, y, LeftToCol | CenterOnRow - ); - PCF_FontWriteNumberAt(font, - ¤t_grad, TypeInt, 2, - tcol, false, rv, - middle_x + (57-1)/2 + 4, y, RightToCol | CenterOnRow - ); - } - current_grad += 10; - } - } - - /*Go downwards*/ - current_grad = 0; - for(y = middle_y; y < rv->h-yoffset; y++){ - if((y-middle_y) % (4*ppm) == 0){ // 10 graduation - if(current_grad > 0){ - PCF_FontWriteNumberAt(font, - ¤t_grad, TypeInt, 2, - tcol, false, rv, - middle_x - (57-1)/2 - 4, y, LeftToCol | CenterOnRow - ); - PCF_FontWriteNumberAt(font, - ¤t_grad, TypeInt, 2, - tcol, false, rv, - middle_x + (57-1)/2 + 4, y, RightToCol | CenterOnRow - ); - } - current_grad += 10; - } - } - - return rv; -} - - -/*TODO: This might go in a Ruler class*/ -int attitude_indicator_resolve_value(AttitudeIndicator *self, float value) -{ - float aval; - float ngrads; - - aval = fabs(value); - if(aval == 0){ - ngrads = 0; - }else if(!fmod(aval, 2.5)){ - ngrads = aval/2.5; - }else if(!fmod(aval, 5.0)){ - ngrads = aval/5; - }else if(!fmod(aval, 10)){ - ngrads = aval/10; - }else { - ngrads = aval/2.5; - } - - return self->common_center.y + sign(value) * round((ngrads * 9.0)); -} - -/*TODO: This might go in a Ruler class*/ - -/* Returns a y increment from the position where the ball horizon is aligned with - * the view "rubis". - * */ -int attitude_indicator_resolve_increment(AttitudeIndicator *self, float value) -{ - float aval; - float ngrads; - - aval = fabs(value); - if(aval == 0){ - ngrads = 0; - }else if(!fmod(aval, 2.5)){ - ngrads = aval/2.5; - }else if(!fmod(aval, 5.0)){ - ngrads = aval/5; - }else if(!fmod(aval, 10)){ - ngrads = aval/10; - }else { - ngrads = aval/2.5; - } - - return sign(value) * round((ngrads * 9.0)); -} - - - -static SDL_Surface *attitude_indicator_get_etched_ball(AttitudeIndicator *self) -{ - if(!self->etched_ball.canvas){ - SDL_Surface *ball, *ruler; - SDL_Rect ball_pos; - SDL_Rect ruler_pos; - - ball = attitude_indicator_draw_ball(self); - ruler = attitude_indicator_draw_ruler(self, self->size, 9, resource_manager_get_font(TERMINUS_12), &SDL_WHITE); - - generic_layer_init(&self->etched_ball, self->ball_all.w, self->ball_all.h); - - /* First place the ball and the scale, such has the middle of the the scale is on - * the same line as the "middle" of the ball. They both need to have the same y coordinate - * on screen. - * */ - SDL_BlitSurface(ball, NULL, self->etched_ball.canvas, NULL); - - ruler_pos.x = round(self->ball_all.w/2.0) - self->ruler_center.x; - ruler_pos.y = self->ball_horizon - self->ruler_center.y; - - SDL_BlitSurface(ruler, NULL, self->etched_ball.canvas, &ruler_pos); - - SDL_FreeSurface(ball); - SDL_FreeSurface(ruler); - } - generic_layer_build_texture(&self->etched_ball); - - return self->etched_ball.canvas; -} - -static void attitude_indicator_update_state(AttitudeIndicator *self, Uint32 dt) -{ - BaseAnimation *animation; - - if(BASE_GAUGE(self)->nanimations > 0){ - animation = BASE_GAUGE(self)->animations[0]; - if(!animation->finished){ - BASE_GAUGE(self->rollslip)->dirty = true; - } - } - - /*First find out a view-sized window into the larger ball buffer for a 0deg pitch*/ - self->state.win = (SDL_Rect){ - .x = self->ball_center.x - (round(base_gauge_w(BASE_GAUGE(self))/2.0) -1), /*Is ball_window useless?*/ - .y = self->ball_center.y - (self->common_center.y - 1), - .w = base_gauge_w(BASE_GAUGE(self)), - .h = base_gauge_h(BASE_GAUGE(self)) - }; - /*Then apply to correct y offset to account for pitch*/ - self->state.win.y += attitude_indicator_resolve_increment(self, self->pitch * -1.0); - - /* Now that we have the correct self->state.window, rotate it to account for roll - * The rotation center must be 40% of the height and middle width - * */ - self->state.rcenter = (SDL_Point){ - .x = self->state.win.x + (round(self->state.win.w/2.0)-1), - .y = self->state.win.y + (round(self->state.win.h*0.4)-1) - }; - - self->state.dst_clip = (SDL_Rect){ - self->state.rcenter.x - self->state.win.x, - self->state.rcenter.y - self->state.win.y, - 0,0 - }; -#if !USE_SDL_GPU - if(self->roll != 0){ - SDL_RenderCopyEx(self->renderer, self->ball_texture, - NULL, NULL, - self->roll, &self->state.rcenter, - SDL_FLIP_NONE - ); - }else{ - SDL_BlitSurface(self->etched_ball.canvas, NULL, self->state.rbuffer, NULL); - } -#endif -#if ENABLE_3D - int horizon_y = self->common_center.y-1; - int increment = 0; - increment = self->pitch * 7; /*7 pixels 1 degree*/ - horizon_y += increment; - - /*TODO: This Whole infinite horizon handling code - * should go in a common looping ruler handler - * that can handle both this and DigitBarrel - */ - /*Resolve the heading value in a pixel x-coordinate in the image*/ - int value_x = 0; - if(self->heading >= 0 && self->heading <= 230){ - value_x = 1024 + self->heading / (1.0/8.0); /*degrees per pixel*/ - }else if(self->heading >= 232 && self->heading <= 359){ - float tmp = self->heading - 232; - value_x = 0 + tmp / (1.0/8.0); - } - - /* - * Postionning / centering to have - * hz_srect.x + rubis = value_x - */ - int rubis = self->common_center.x; - int xbegin = value_x - rubis; - int xend; - bool rpatch; - int xcursor = 0; - SDL_Rect hz_srects[3]; - SDL_Rect hz_drects[3]; - int npatches = 0; - - if(xbegin < 0){ /* we went before the image begining and need to fill the left side*/ - hz_srects[npatches].x = self->horizon_src->w-1 - abs(xbegin); - hz_srects[npatches].w = abs(xbegin); - hz_srects[npatches].y = 0; - hz_srects[npatches].h = self->horizon_src->h; - - hz_drects[npatches].x = xcursor; - hz_drects[npatches].w = hz_srects[npatches].w; - //hz_drects[npatches].y = horizon_y - self->horizon_src->h; - hz_drects[npatches].y = generic_layer_h(&self->phh_overlay)/2-1 - - hz_srects[npatches].h; - hz_drects[npatches].h = self->horizon_src->h; - - xcursor += hz_drects[npatches].w; - xbegin = 0; - npatches++; - } - hz_srects[npatches].x = xbegin; - hz_srects[npatches].w = generic_layer_w(&self->phh_overlay); - hz_srects[npatches].y = 0; - hz_srects[npatches].h = self->horizon_src->h; - - xend = hz_srects[npatches].x + hz_srects[npatches].w; - if(xend > self->horizon_src->w-1){ - hz_srects[npatches].w = self->horizon_src->w - hz_srects[npatches].x; - } - - hz_drects[npatches].x = xcursor; - hz_drects[npatches].w = hz_srects[npatches].w; - hz_drects[npatches].y = generic_layer_h(&self->phh_overlay)/2-1 - - hz_srects[npatches].h; - hz_drects[npatches].h = self->horizon_src->h; - - xcursor += hz_drects[npatches].w; - npatches++; - - if(xend > self->horizon_src->w-1){ - int pixels = xend - self->horizon_src->w-1; - hz_srects[npatches].x = 0; - hz_srects[npatches].w = pixels; - hz_srects[npatches].y = 0; - hz_srects[npatches].h = self->horizon_src->h; - - hz_drects[npatches].x = xcursor; - hz_drects[npatches].w = hz_srects[npatches].w; - hz_drects[npatches].y = generic_layer_h(&self->phh_overlay)/2-1 - - hz_srects[npatches].h; - hz_drects[npatches].h = self->horizon_src->h; - - npatches++; - } - - if(!self->phh_inited){ - /*First time, draw the full overlay*/ - SDL_FillRect(self->phh_overlay.canvas, NULL, 0x00000000); - for(int i = 0; i < npatches; i++){ - SDL_BlitSurface( - self->horizon_src, &hz_srects[i], - self->phh_overlay.canvas, &hz_drects[i] - ); - } - - SDL_Rect pitch_loc = { - .x = generic_layer_w(&self->phh_overlay)/2 - 1 - - self->pitch_ruler->w/2 + 1, - .y = 0, - .w = self->pitch_ruler->w, - .h = self->pitch_ruler->h - }; - SDL_BlitSurface(self->pitch_ruler, NULL, - self->phh_overlay.canvas, &pitch_loc); - self->phh_inited = true; - }else{ - /* Then only redraw the changed parts. - * Around 800x(!) faster measured on 1k/2k frames*/ - SDL_Rect hhz_line = { - .x = 0, - .y = generic_layer_h(&self->phh_overlay)/2-1 - - self->horizon_src->h, - .w = generic_layer_w(&self->phh_overlay), - .h = self->horizon_src->h - }; - for(int i = 0; i < npatches; i++){ - SDL_BlitSurface( - self->horizon_src, &hz_srects[i], - self->phh_overlay.canvas, &hz_drects[i] - ); - } - - SDL_Rect pitch_src = { - .x = 0, - .y = self->pitch_ruler->h/2 - self->horizon_src->h, - .w = self->pitch_ruler->w, - .h = self->horizon_src->h - }; - SDL_Rect pitch_loc = { - .x = generic_layer_w(&self->phh_overlay)/2 - 1 - - self->pitch_ruler->w/2 + 1, - .y = generic_layer_h(&self->phh_overlay)/2-1 - - self->horizon_src->h, - .w = self->pitch_ruler->w, - .h = self->horizon_src->h - }; - SDL_BlitSurface(self->pitch_ruler, &pitch_src, - self->phh_overlay.canvas, &pitch_loc); - } - generic_layer_update_texture(&self->phh_overlay); - - self->state.phh_drect = (SDL_Rect){ - .x = base_gauge_w(BASE_GAUGE(self))/2 - self->phh_overlay.texture->w/2 + 1, - .y = horizon_y - (self->phh_overlay.texture->h/2-1), - .w = self->phh_overlay.texture->w, - .h = self->phh_overlay.texture->h - }; - - self->state.phh_rcenter.x = self->phh_overlay.texture->w/2; - self->state.phh_rcenter.y = self->phh_overlay.texture->h/2 - increment; -#endif //ENABLE_3D -} - -static void attitude_indicator_render(AttitudeIndicator *self, Uint32 dt, RenderContext *ctx) -{ -#if USE_SDL_GPU - if(self->mode == AI_MODE_2D){ - base_gauge_blit_rotated_texture(BASE_GAUGE(self), ctx, - self->etched_ball.texture, - NULL, - -self->roll, - &self->state.rcenter, - NULL, - &self->state.dst_clip); - }else{ -#if ENABLE_3D - base_gauge_blit_rotated_texture(BASE_GAUGE(self), ctx, - self->phh_overlay.texture, - NULL, - -self->roll, - &self->state.phh_rcenter, - &self->state.phh_drect, - NULL - ); - -#endif - } -#else - base_gauge_blit(BASE_GAUGE(self), ctx, - self->state.rbuffer, - &self->state.win, - NULL - ); -#endif - base_gauge_blit_layer(BASE_GAUGE(self), ctx, &self->markers[MARKER_LEFT], NULL, &self->locations[MARKER_LEFT]); - base_gauge_blit_layer(BASE_GAUGE(self), ctx, &self->markers[MARKER_RIGHT], NULL, &self->locations[MARKER_RIGHT]); - base_gauge_blit_layer(BASE_GAUGE(self), ctx, &self->markers[MARKER_CENTER], NULL, &self->locations[MARKER_CENTER]); -} diff --git a/attitude-indicator.h b/attitude-indicator.h deleted file mode 100644 index 60a0dd4..0000000 --- a/attitude-indicator.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef ATTITUDE_INDICATOR_H -#define ATTITUDE_INDICATOR_H - -#include "base-gauge.h" -#include "generic-layer.h" -#include "roll-slip-gauge.h" -#include - -#define MARKER_LEFT 0 -#define MARKER_RIGHT 1 -#define MARKER_CENTER 2 -#define ROLL_SLIP 3 -#define LOCATION_MAX 5 - -typedef enum{ - AI_ROLL_ANIMATION, - AI_PITCH_ANIMATION, - N_AI_ANIMATIONS -}AIttitudeIndicatorAnimation; - -typedef enum{ - AI_MODE_2D = 0, - AI_MODE_3D -}AttitudeIndicatorDisplayMode; - -typedef struct{ - SDL_Point rcenter; - SDL_Rect dst_clip; - SDL_Rect win; -#if !USE_SDL_GPU - SDL_Surface *rbuffer; /*rotation buffer*/ -#endif -#if ENABLE_3D - SDL_Rect phh_drect; - SDL_Point phh_rcenter; -#endif -}AttitudeIndicatorState; - -typedef struct{ - BaseGauge super; - SDL_Point common_center; - uint32_t diagonal; - - float roll; /*pitch?*/ - float pitch; - float heading; - - RollSlipGauge *rollslip; - - int size; /*number of 10s markings*/ - AttitudeIndicatorDisplayMode mode; - - SDL_Rect ball_window; /*Visible portion*/ - SDL_Rect ball_all; /*Visible portion plus extended area*/ - int ball_horizon; - SDL_Point ball_center; - - SDL_Point ruler_center; - int ruler_middle; - int ruler_middlex; - - GenericLayer markers[3]; //left, right, center - SDL_Rect locations[LOCATION_MAX]; -#if !USE_SDL_GPU - SDL_Renderer *renderer; - SDL_Texture *ball_texture; -#endif - - GenericLayer etched_ball; -#if USE_SDL_GPU && ENABLE_3D - SDL_Surface *horizon_src; - SDL_Surface *pitch_ruler; /*pitch ruler*/ - - GenericLayer phh_overlay; /*pitch/horizon/heading*/ - bool phh_inited; -#endif - - AttitudeIndicatorState state; -}AttitudeIndicator; - - -AttitudeIndicator *attitude_indicator_new(int width, int height); -AttitudeIndicator *attitude_indicator_init(AttitudeIndicator *self, int width, int height); - -bool attitude_indicator_set_roll(AttitudeIndicator *self, float value, bool animated); -bool attitude_indicator_set_pitch(AttitudeIndicator *self, float value, bool animated); -bool attitude_indicator_set_heading(AttitudeIndicator *self, float value); - -AttitudeIndicator *attitude_indicator_init(AttitudeIndicator *self, int width, int height); - -#endif /* ATTITUDE_INDICATOR_H */ diff --git a/base-animation.c b/base-animation.c deleted file mode 100644 index e1d5411..0000000 --- a/base-animation.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include - -#include "base-animation.h" - -static inline void base_animation_process_floats(BaseAnimation *self, float increment); - - -BaseAnimation *base_animation_new(ValueType type, size_t ntargets, ...) -{ - va_list args; - BaseAnimation *self, *rv; - - self = calloc(1, sizeof(BaseAnimation)); - if(self){ - va_start(args, ntargets); - rv = base_animation_vainit(self, type, ntargets, args); - va_end(args); - if(!rv){ - free(self); - return NULL; - } - } -// printf("BaseAnimation %p: allocated\n", self); - return self; -} - -/** - * @brief Inits a BaseAnimation to animate a set of targets - * - * Targets are pointers to the value(s) to animate - * - * - * - * - */ -BaseAnimation *base_animation_init(BaseAnimation *self, ValueType type, size_t ntargets, ...) -{ - BaseAnimation *rv; - va_list args; - - va_start(args, ntargets); - rv = base_animation_vainit(self, type, ntargets, args); - va_end(args); - - return self; -} - -BaseAnimation *base_animation_vainit(BaseAnimation *self, ValueType type, size_t ntargets, va_list ap) -{ - self->ntargets = ntargets; - self->targets_type = type; - self->targets = calloc(self->ntargets, sizeof(void*)); - if(!self->targets) - return NULL; - - for(int i = 0; i < ntargets; i++){ - self->targets[i] = va_arg(ap, void*); - } - return self; -} - -BaseAnimation *base_animation_dispose(BaseAnimation *self) -{ - if(self->targets) - free(self->targets); - return self; -} - -void base_animation_unref(BaseAnimation *self) -{ - if(--self->refcount == 0){ -// printf("BaseAnimation %p: freeing\n", self); - free(base_animation_dispose(self)); - }else{ - /*printf("BaseAnimation %p: not freed, refcount is %d (was %d)\n",*/ - /*self, self->refcount,*/ - /*self->refcount+1*/ - /*);*/ - } -} - -void base_animation_ref(BaseAnimation *self) -{ - self->refcount++; -} - -void base_animation_start(BaseAnimation *self, float from, float to, float duration) -{ - self->start = from; - self->end = to; - self->duration = duration; - self->time_progress = 0.0; - self->finished = false; - self->last_value_reached = false; -} - -/** - * - * - * @param dt time elapsed since last call (milliseconds) - * @return value matching the given time - * */ -bool base_animation_loop(BaseAnimation *self, uint32_t dt) -{ - float progress; - float dv; - float new_value; - - /* We don't set finished when setting the last value - * to be called one more time to allow gauges that have - * children to process the last value. - * Otherwise self->finished whould be true in the gauge's - * update_state during the iteration where the last value - * has been reached - */ - if(self->last_value_reached){ - self->finished = true; - return false; - } - - self->time_progress += dt; //millis - progress = self->time_progress / self->duration; /*percentage*/ - if(progress > 1.0f) - progress = 1.0f; - - dv = self->end - self->start; - new_value = self->start + dv * progress; - if(self->targets_type == TYPE_FLOAT){ - base_animation_process_floats(self, new_value); - } - return true; -} - -static inline void base_animation_process_floats(BaseAnimation *self, float new_value) -{ - for(int i = 0; i < self->ntargets; i++){ - *((float *)self->targets[i]) = new_value; - } - if(new_value == self->end) - self->last_value_reached = true; -} diff --git a/base-animation.h b/base-animation.h deleted file mode 100644 index 737c163..0000000 --- a/base-animation.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef BASE_ANIMATION_H -#define BASE_ANIMATION_H - -#include -#include -#include -#include - -#define DEFAULT_DURATION 1000 /*milliseconds*/ - -/* BaseAnimation can be extended in the future (if needed) - * by making base_animation_loop virtual there is no need - * for that at the moment and doing it would add an additional - * indirection each frame. - */ - -typedef enum{ - TYPE_INT8, - TYPE_UINT8, - TYPE_INT16, - TYPE_UINT16, - TYPE_INT32, - TYPE_UINT32, - TYPE_FLOAT, - TYPE_DOUBLE, - N_TYPES -}ValueType; - -typedef struct{ - /* targets, floats only now - * will be generic using a void** - * and a type enum to handle all - * numeric types. - * */ - float **targets; - ValueType targets_type; - size_t ntargets; - - /*values*/ - float start; - float end; - - /*milliseconds*/ - float duration; - float time_progress; - - bool finished; - bool last_value_reached; - size_t refcount; /*must be the same type as ntargets*/ -}BaseAnimation; - -BaseAnimation *base_animation_new(ValueType type, size_t ntargets, ...); -BaseAnimation *base_animation_init(BaseAnimation *self, ValueType type, size_t ntargets, ...); -BaseAnimation *base_animation_vainit(BaseAnimation *self, ValueType type, size_t ntargets, va_list ap); - -void base_animation_unref(BaseAnimation *self); -void base_animation_ref(BaseAnimation *self); - -void base_animation_start(BaseAnimation *self, float from, float to, float duration); -bool base_animation_loop(BaseAnimation *self, uint32_t dt); -#endif /* BASE_ANIMATION_H */ diff --git a/base-gauge.c b/base-gauge.c deleted file mode 100644 index c037b5a..0000000 --- a/base-gauge.c +++ /dev/null @@ -1,557 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include - -#include "SDL_gpu.h" - -#include "SDL_rect.h" -#include "base-gauge.h" -#include "misc.h" -#include "sdl-colors.h" -#include "view.h" - -#define ALLOC_CHUNK 4 -#define ENABLE_SDL_GPU_FUNNY_COORDS 1 - -BaseGauge *base_gauge_init(BaseGauge *self, BaseGaugeOps *ops, int w, int h) -{ - self->frame.w = w; - self->frame.h = h; - - self->ops = ops; - self->dirty = true; - - return self; -} - -/** - * @brief Release all resources held by @param self - * - * This function will free any children and animations that @self holds. - * - * Subclasses of BaseGauge *can* provide a hook through base_gauge_ops - * .dispose *if* they need to free specific resources (SDL_Surfaces, - * char*, ...). - * - * If a Subclass only holds references to other BaseGauge-derived types - * *and* that these have been added as childs with @see base_gauge_add_child - * they'll be automatically freed and you just need to pass NULL as the - * dispose op. - * - * If you derive a type that have already provided a hook, you are supposed - * to chain-up (call the parent type dispose function) in your own dispose hook. - * You can either: - * a) Call the function if super's dispose do have a symbol, i.e. is not static - * b) Copy the function pointer from super's BaseGaugeOps after super's init. - * see softkey_init function for an example of that. - * - * @param self a BaseGauge - * @return always self (convenience) - */ -void *base_gauge_dispose(BaseGauge *self) -{ - for(int i = 0; i < self->nchildren; i++) - base_gauge_free(self->children[i]); - - for(int i = 0; i < self->nanimations; i++){ - base_animation_unref(self->animations[i]); - } - - if(self->children) - free(self->children); - if(self->animations) - free(self->animations); - - if(self->ops->dispose) - self->ops->dispose(self); - return self; -} - -/** - * @brief adds a child - * - * - */ -bool base_gauge_add_child(BaseGauge *self, BaseGauge *child, int x, int y) -{ - /* This is not very good... it would be better to avoid dynamic allocation - * and have that known/fixed on init. Also hurts data locality. Having - * everything within/aside the struct would be nice */ - if(self->nchildren == self->children_size){ - void *tmp; - self->children_size += ALLOC_CHUNK; - tmp = realloc(self->children, sizeof(BaseGauge*)*self->children_size); - if(!tmp){ - self->children_size -= ALLOC_CHUNK; - return false; - } - self->children = tmp; - } - self->children[self->nchildren] = child; - child->frame.x = x; - child->frame.y = y; - child->parent = self; - self->nchildren++; - - return true; -} - -/** - * @brief Moves a child gauge relative to @self. - * Same as @see base_gauge_move but first checks if @child is a child of @self. - * - */ -bool base_gauge_move_child(BaseGauge *self, BaseGauge *child, int new_x, int new_y) -{ - self->frame.x = new_x; - self->frame.y = new_y; - BaseGauge *found = NULL; - for(int i = 0; i < self->nchildren && !found; i++){ - found = self->children[i] == child ? child : NULL; - } - if(!found) return false; - - return true; -} - -/** - * @brief Moves the gauge relative to (within) its parent. - * Does no checks, use @see base_gauge_move_child for a parent-child - * checking version. - * - * TODO: inline ? - */ -void base_gauge_move(BaseGauge *self, int new_x, int new_y) -{ - self->frame.x = new_x; - self->frame.y = new_y; -} - -/** - * @brief Moves the gauge relative to (within) its parent by @xinc and @yinc incremebnts. - * Does no checks, use @see base_gauge_move_child for a parent-child checking version. - * - * TODO: inline ? - */ -void base_gauge_move_by(BaseGauge *self, int xinc, int yinc) -{ - self->frame.x += xinc; - self->frame.y += yinc; -} - - -/** - * @brief Adds an animation to the gauge. - * - * Takes ownership of the animation, you must unref it after calling the function? - * TODO during refactor: check how that works out - * - * - */ -bool base_gauge_add_animation(BaseGauge *self, BaseAnimation *animation) -{ - /* This is not very good... it would be better to avoid dynamic allocation - * and have that known/fixed on init. Also hurts data locality. Having - * everything within/aside the struct would be nice */ - if(self->nanimations == self->animations_size){ - void *tmp; - self->animations_size += ALLOC_CHUNK; - tmp = realloc(self->animations, sizeof(BaseAnimation*)*self->animations_size); - if(!tmp){ - self->animations_size -= ALLOC_CHUNK; - return false; - } - self->animations = tmp; - } - self->animations[self->nanimations] = animation; - base_animation_ref(animation); - self->nanimations++; - - return true; -} - - -void base_gauge_render(BaseGauge *self, Uint32 dt, RenderContext *ctx) -{ - bool rv; - for(int i = 0; i < self->nanimations; i++){ - if(!self->animations[i]->finished){ - rv = base_animation_loop(self->animations[i], dt); - /*If at least one animation has changed something - * we need to retrace */ - if(rv) - self->dirty = true; - } - } - if(self->dirty){ - if(self->ops->update_state) - self->ops->update_state(self, dt); - self->dirty = false; - } - if(self->ops->render) - self->ops->render(self, dt, ctx); - for(int i = 0; i < self->nchildren; i++){ - SDL_Rect child_location = { - .x = ctx->location->x + self->children[i]->frame.x, - .y = ctx->location->y + self->children[i]->frame.y, - /*The following are only here to prevent distortion when using - * SDL_Renderer/SDL_Gpu/OpenGL */ - .w = self->children[i]->frame.w, - .h = self->children[i]->frame.h, - }; - /* TODO during refactor: portion will be NULL during the refactor, afterwise compute - * the correct portion for the child if needed */ - /*TODO refactor: Unroll recursivity*/ - base_gauge_render(self->children[i], dt, &(RenderContext){ - .target = ctx->target, - .location = &child_location, - .portion = ctx->portion - }); - } -} - -/*******TAKEN FROM BUFFERED_GAUGE**************/ - - -/** - * @brief Does a blit from the gauge to @p location using a GenericLayer - * (encapsulates surface+texture) as source. - * - * @param self a RenderTarget - * @param location The area within the RenderTarget to blit to - * @param src The GenericLayer to blit from - * @param srcrect The area of @p src to copy (in @p src coordinate space, - * i.e 0,0 is @p src top left corner) - * @param dstrect The area to blit to, in the gauge virtual coordinate - * space, i.e 0,0 is the gauge top-left corner and will be offseted by - * location. - * @param portion The portion of the gauge to blit. NULL for whole - * @return The underlying lib return value. - * - * TODO: INLINE - */ -int base_gauge_blit_layer(BaseGauge *self, RenderContext *ctx, - GenericLayer *src, - SDL_Rect *srcrect, SDL_Rect *dstrect) -{ -#if USE_SDL_GPU - return base_gauge_blit_texture(self, ctx, src->texture, srcrect, dstrect); -#else - return base_gauge_blit(self, ctx, src->canvas, srcrect, dstrect); -#endif -} - -#define rectf_offset(r1, r2) ((GPU_Rect){(r1)->x + (r2)->x, (r1)->y + (r2)->y, (r1)->w, (r1)->h}) -#define rect_offset(r1, r2) ((SDL_Rect){(r1)->x + (r2)->x, (r1)->y + (r2)->y, (r1)->w, (r1)->h}) -#define rectf(r) (GPU_Rect){(r)->x, (r)->y, (r)->w, (r)->h} -int base_gauge_blit_texture(BaseGauge *self, RenderContext *ctx, - GPU_Image *src, SDL_Rect *srcrect, - SDL_Rect *dstrect) -{ - /*TODO: direct GPU_Rect for SDL_gpu*/ - SDL_Rect fdst; /*Final destination*/ - - if(dstrect){ - fdst = rect_offset(dstrect, ctx->location); - }else{ - fdst = (SDL_Rect){ - .x = 0, - .y = 0, - .w = base_gauge_w(self), - .h = base_gauge_h(self) - }; - fdst = rect_offset(&fdst, ctx->location); - } - -#if 1 -// printf("Before clipping: "); -// SDLExt_RectDump(&fdst); - - /*Auto clip dest to source to avoid unwanted scaling*/ - if(srcrect){ - fdst.w = fdst.w > srcrect->w ? srcrect->w : fdst.w; - fdst.h = fdst.h > srcrect->h ? srcrect->h : fdst.h; - } -// printf("After clipping: "); -// SDLExt_RectDump(&fdst); -#endif - float x,y; - - if(!srcrect){ - x = src->w/2.0 + fdst.x; - y = src->h/2.0 + fdst.y; - }else{ - x = srcrect->w/2.0 + fdst.x; - y = srcrect->h/2.0 + fdst.y; - } -#if 0 - printf( - "GPU_Blit from %p {.x:%d, .y:%d, .w:%d, .h:%d} to %p x:%0.2f y:%0.2f\n", - src, - srcrect->x,srcrect->y, - srcrect->w,srcrect->h, - ctx->target.target, x, y - ); -#endif - GPU_Blit(src, srcrect ? &rectf(srcrect) : NULL, ctx->target.target, x, y); - return 0; -} - -int base_gauge_blit(BaseGauge *self, RenderContext *ctx, - SDL_Surface *src, SDL_Rect *srcrect, - SDL_Rect *dstrect) -{ - /*TODO: direct GPU_Rect for SDL_gpu*/ - SDL_Rect fdst; /*Final destination*/ - - if(dstrect){ - fdst = rect_offset(dstrect, ctx->location); - }else{ - fdst = (SDL_Rect){ - .x = 0, - .y = 0, - .w = base_gauge_w(self), - .h = base_gauge_h(self) - }; - fdst = rect_offset(&fdst, ctx->location); - } - - return SDL_BlitSurface(src, srcrect, ctx->target.surface, &fdst); -} - -/** - * TODO: color should be a union of possible types - */ -void base_gauge_fill(BaseGauge *self, RenderContext *ctx, - SDL_Rect *area, void *color, bool packed) -{ - /*TODO: direct GPU_Rect for SDL_gpu*/ - SDL_Rect farea; /*final area*/ - - if(area){ - farea = rect_offset(area, ctx->location); - }else{ - farea = (SDL_Rect){ - .x = 0, - .y = 0, - .w = base_gauge_w(self), - .h = base_gauge_h(self) - }; - farea = rect_offset(&farea, ctx->location); - } - -#if USE_SDL_GPU - if(!color) - return; - if(packed){ - printf("Packed colors not supported with SDL_gpu\n"); - } - - GPU_RectangleFilled2(ctx->target.target, rectf(&farea), *(SDL_Color*)color); -#else - if(!color){ - SDL_FillRect(ctx->target.surface, &farea, SDL_UCKEY(ctx->target.surface)); - return; - } - - if(packed){ - SDL_FillRect(ctx->target.surface, &farea, *((Uint32*)color)); - }else{ - SDL_FillRect(ctx->target.surface, - &farea, - SDL_MapRGBA(ctx->target.surface->format, - ((SDL_Color*)color)->r, - ((SDL_Color*)color)->g, - ((SDL_Color*)color)->b, - ((SDL_Color*)color)->a - ) - ); - } -#endif -} - -void base_gauge_draw_rubis(BaseGauge *self, RenderContext *ctx, - int y, SDL_Color *color, int pskip) -{ - SDL_Rect area; - - area = (SDL_Rect){ - .x = 0, - .y = 0, - .w = base_gauge_w(self), - .h = base_gauge_h(self) - }; - area = rect_offset(&area, ctx->location); - -#if USE_SDL_GPU - int startx, stopx; - int restartx, endx; - int liney, half; - - startx = area.x; - endx = area.x + area.w; - liney = y + area.y; - - half = round(pskip/2.0); - stopx = startx + half; - restartx = endx - half; - - /* - printf("%s, pushing line from (x:%d,y:%d) to (x:%d,y:%d)\n",__FUNCTION__,startx,liney,stopx,liney); - printf("%s, pushing line from (x:%d,y:%d) to (x:%d,y:%d)\n",__FUNCTION__,restartx,liney,endx,liney);*/ -#if ENABLE_SDL_GPU_FUNNY_COORDS - /* SDL_GPU has y=0 out of the screen and w,h in the screen - * like x is [x1, x2[ and y ? - * */ - liney++; -#endif - GPU_Line(ctx->target.target, startx, liney, stopx, liney, *color); - GPU_Line(ctx->target.target, restartx, liney, endx, liney, *color); -#else - view_draw_rubis(ctx->target.surface, y, color, pskip, &area); -#endif -} - -void base_gauge_draw_outline(BaseGauge *self, RenderContext *ctx, SDL_Color *color, SDL_Rect *area) -{ - /*TODO: direct GPU_Rect for SDL_gpu*/ - SDL_Rect farea; /*final area*/ - - if(area){ - farea = rect_offset(area, ctx->location); - }else{ - farea = (SDL_Rect){ - .x = 0, - .y = 0, - .w = base_gauge_w(self), - .h = base_gauge_h(self) - }; - farea = rect_offset(&farea, ctx->location); - } -#if USE_SDL_GPU - /*SDL_GPU treats coordinates as inclusive*/ - farea.x++; - farea.y++; - farea.w--; - farea.h--; - - GPU_Rectangle2(ctx->target.target, rectf(&farea), *color); -#else - view_draw_outline(ctx->target.surface, color, &farea); -#endif -} - -void base_gauge_draw_static_font_patch(BaseGauge *self, RenderContext *ctx, - PCF_StaticFont *font, - PCF_StaticFontPatch *patch) -{ - SDL_Rect dst_rect; /*final destination*/ - SDL_Rect src_rect; - - src_rect = (SDL_Rect){ - .x = patch->src.x, - .y = patch->src.y, - .w = font->metrics.characterWidth, - .h = font->metrics.ascent + font->metrics.descent - }; - - dst_rect = (SDL_Rect){ - .x = patch->dst.x, - .y = patch->dst.y, - .w = font->metrics.characterWidth, - .h = font->metrics.ascent + font->metrics.descent - }; - -#if USE_SDL_GPU - if(!font->texture) /*TODO refactor: Have this a pre-requisite*/ - PCF_StaticFontCreateTexture(font); - - base_gauge_blit_texture(self, ctx, font->texture, &src_rect, &dst_rect); -#else - base_gauge_blit(self, ctx, font->raster, &src_rect, &dst_rect); -#endif -} - -void base_gauge_draw_static_font_rect_patch(BaseGauge *self, RenderContext *ctx, - PCF_StaticFont *font, - PCF_StaticFontPatch *patch) -{ - SDL_Rect dst_rect; /*final destination*/ - SDL_Rect src_rect; - - src_rect = (SDL_Rect){ - .x = patch->src.x, - .y = patch->src.y, - .w = patch->src.w, - .h = patch->src.h - }; - - dst_rect = (SDL_Rect){ - .x = patch->dst.x, - .y = patch->dst.y, - .w = patch->src.w, - .h = patch->src.h - }; - -#if USE_SDL_GPU - if(!font->texture) /*TODO refactor: Have this a pre-requisite*/ - PCF_StaticFontCreateTexture(font); - - base_gauge_blit_texture(self, ctx, font->texture, &src_rect, &dst_rect); -#else - base_gauge_blit(self, ctx, font->raster, &src_rect, &dst_rect); -#endif -} - - -int base_gauge_blit_rotated_texture(BaseGauge *self, RenderContext *ctx, - GPU_Image *src, SDL_Rect *srcrect, - double angle, SDL_Point *about, - SDL_Rect *dstrect, SDL_Rect *clip) -{ - SDL_Rect fdst; /*final destination*/ - SDL_Rect fclip; /*final clip*/ - - if(dstrect){ - fdst = rect_offset(dstrect, ctx->location); - }else{ - fdst = (SDL_Rect){ - .x = 0, - .y = 0, - .w = base_gauge_w(self), - .h = base_gauge_h(self) - }; - fdst = rect_offset(&fdst, ctx->location); - } - if(clip) - fclip = rect_offset(clip, ctx->location); - - about = about ? about : (srcrect ? &(SDL_Point){.x = srcrect->w/2, .y = srcrect->h/2} - : &(SDL_Point){.x = src->w/2, .y = src->h/2}); - - if(!clip){ - GPU_BlitRectX(src, - srcrect ? &rectf(srcrect) : NULL, - ctx->target.target, - &rectf(&fdst), - angle, - about->x, about->y, - GPU_FLIP_NONE - ); - }else{ - GPU_BlitTransformX(src, - srcrect ? &rectf(srcrect) : NULL, - ctx->target.target, - fclip.x, fclip.y, - about->x, about->y, - angle, 1,1 - ); - } - return 1; -} diff --git a/base-gauge.h b/base-gauge.h deleted file mode 100644 index 7e7892c..0000000 --- a/base-gauge.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef BASE_GAUGE_H -#define BASE_GAUGE_H - -#include -#include - -#include "SDL_pcf.h" -#include "base-animation.h" -#include "generic-layer.h" - -typedef union{ - SDL_Surface *surface; - GPU_Target* target; -}RenderTarget /*__attribute__ ((__transparent_union__))*/; - -typedef struct{ - RenderTarget target; - SDL_Rect *location; /*Location within the target, in target coord space*/ - - SDL_Rect *portion; /*Portion of the gauge to render*/ -}RenderContext; - -typedef void (*RenderFunc)(void *self, Uint32 dt, RenderContext *ctx); -typedef void (*StateUpdateFunc)(void *self, Uint32 dt); -typedef void* (*DisposeFunc)(void *self); - -typedef struct{ - RenderFunc render; - StateUpdateFunc update_state; - - DisposeFunc dispose; -}BaseGaugeOps; - -typedef struct _BaseGauge{ - BaseGaugeOps *ops; - - /*width, height and xy position relative to parent*/ - SDL_Rect frame; - - bool dirty; - - struct _BaseGauge *parent; - - struct _BaseGauge **children; - size_t nchildren; - size_t children_size; /*allocated children*/ - - BaseAnimation **animations; - size_t nanimations; - size_t animations_size; /*allocated animations*/ -}BaseGauge; - -#define BASE_GAUGE_OPS(self) ((BaseGaugeOps*)(self)) -#define BASE_GAUGE(self) ((BaseGauge *)(self)) - -#define base_gauge_w(self) ((self)->frame.w) -#define base_gauge_h(self) ((self)->frame.h) -#define base_gauge_center_y(self) ((base_gauge_h((self))-1)/2) -#define base_gauge_center_x(self) ((base_gauge_w((self))-1)/2) - -BaseGauge *base_gauge_init(BaseGauge *self, BaseGaugeOps *ops, int w, int h); -void *base_gauge_dispose(BaseGauge *self); - -/** - * @brief Frees the memory used to store @self and - * any resources it helds. (internally calls @see - * base_gauge_dispose) - * - * @param self a BaseGauge - * @return always NULL (convenience) - */ -static inline void *base_gauge_free(BaseGauge *self) -{ - free(base_gauge_dispose(self)); - return NULL; -} - -bool base_gauge_add_child(BaseGauge *self, BaseGauge *child, int x, int y); -bool base_gauge_add_animation(BaseGauge *self, BaseAnimation *animation); - -void base_gauge_move(BaseGauge *self, int new_x, int new_y); -void base_gauge_move_by(BaseGauge *self, int xinc, int yinc); -bool base_gauge_move_child(BaseGauge *self, BaseGauge *child, int new_x, int new_y); - -void base_gauge_render(BaseGauge *self, Uint32 dt, RenderContext *ctx); - -int base_gauge_blit_layer(BaseGauge *self, RenderContext *ctx, - GenericLayer *src, - SDL_Rect *srcrect, SDL_Rect *dstrect); -int base_gauge_blit_texture(BaseGauge *self, RenderContext *ctx, - GPU_Image *src, SDL_Rect *srcrect, - SDL_Rect *dstrect); -int base_gauge_blit(BaseGauge *self, RenderContext *ctx, - SDL_Surface *src, SDL_Rect *srcrect, - SDL_Rect *dstrect); -void base_gauge_fill(BaseGauge *self, RenderContext *ctx, - SDL_Rect *area, void *color, bool packed); -void base_gauge_draw_rubis(BaseGauge *self, RenderContext *ctx, - int y, SDL_Color *color, int pskip); - -void base_gauge_draw_outline(BaseGauge *self, RenderContext *ctx, - SDL_Color *color, SDL_Rect *area); - -void base_gauge_draw_static_font_patch(BaseGauge *self, RenderContext *ctx, - PCF_StaticFont *font, - PCF_StaticFontPatch *patch); -void base_gauge_draw_static_font_rect_patch(BaseGauge *self, RenderContext *ctx, - PCF_StaticFont *font, - PCF_StaticFontPatch *patch); - -int base_gauge_blit_rotated_texture(BaseGauge *self, RenderContext *ctx, - GPU_Image *src, SDL_Rect *srcrect, - double angle, SDL_Point *about, - SDL_Rect *dstrect, SDL_Rect *clip); -#endif /* BASE_GAUGE_H */ diff --git a/basic-hud.c b/basic-hud.c deleted file mode 100644 index f0a41fb..0000000 --- a/basic-hud.c +++ /dev/null @@ -1,197 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include -#include -#include - -#include "airspeed-indicator.h" -#include "alt-group.h" -#include "attitude-indicator.h" -#include "base-gauge.h" -#include "basic-hud.h" -#include "misc.h" -#include "compass-gauge.h" -#include "roll-slip-gauge.h" -#include "sfv-gauge.h" -#include "tape-gauge.h" - -static BaseGaugeOps basic_hud_ops = { - .render = (RenderFunc)NULL, - .update_state = (StateUpdateFunc)NULL, - .dispose = (DisposeFunc)NULL -}; - - -BasicHud *basic_hud_new(void) -{ - BasicHud *self; - - self = calloc(1, sizeof(BasicHud)); - if(self){ - if(!basic_hud_init(self)){ - return base_gauge_free(BASE_GAUGE(self)); - } - } - return self; -} - - -BasicHud *basic_hud_init(BasicHud *self) -{ - base_gauge_init( - BASE_GAUGE(self), - &basic_hud_ops, - 640, /*Fixed for now, should be made dynamic and set through params*/ - 480 - ); - - self->attitude = attitude_indicator_new(640, 480); - base_gauge_add_child(BASE_GAUGE(self), - BASE_GAUGE(self->attitude), - 0, 0 - ); - - self->altgroup = alt_group_new(); - self->altgroup->altimeter->src = ALT_SRC_GPS; - base_gauge_add_child(BASE_GAUGE(self), - BASE_GAUGE(self->altgroup), - 460, 53 - ); - - self->airspeed = airspeed_indicator_new(50,60,85,155,200); - base_gauge_add_child(BASE_GAUGE(self), - BASE_GAUGE(self->airspeed), - 96, 72 - ); - - self->compass = compass_gauge_new(); - base_gauge_add_child(BASE_GAUGE(self), - BASE_GAUGE(self->compass), - 640/2 - base_gauge_w(BASE_GAUGE(self->compass))/2, - (480-1) - base_gauge_h(BASE_GAUGE(self->compass)) - ); - - - self->locations[ALT_GROUP] = (SDL_Rect){460,53,0,0}; - self->locations[SPEED] = (SDL_Rect){96,72,0,0}; - self->locations[COMPASS] = (SDL_Rect){ - .x = 640/2 - base_gauge_w(BASE_GAUGE(self->compass))/2, - .y = (480-1) - base_gauge_h(BASE_GAUGE(self->compass)), - .w = base_gauge_w(BASE_GAUGE(self->compass)), - .h = base_gauge_h(BASE_GAUGE(self->compass)) - }; - - - return self; -} - -void basic_hud_set(BasicHud *self, int nvalues, ...) -{ - va_list args; - - va_start(args, nvalues); - basic_hud_set_values(self, nvalues, args); - va_end(args); -} - -void basic_hud_set_values(BasicHud *self, int nvalues, va_list ap) -{ - HudValue hv; - double val; - - for(int i = 0; i < nvalues; i++){ - hv = va_arg(ap, HudValue); - val = va_arg(ap, double); - - switch(hv){ - case ALTITUDE: - alt_group_set_altitude(self->altgroup, val); - break; - case VERTICAL_SPEED: - alt_group_set_vertical_speed(self->altgroup, val); - break; - case AIRSPEED: - airspeed_indicator_set_value(self->airspeed, val); - break; - case PITCH: - attitude_indicator_set_pitch(self->attitude, val, true); - break; - case ROLL: - attitude_indicator_set_roll(self->attitude, val, true); - break; - case SLIP: - roll_slip_gauge_set_slip(self->attitude->rollslip, val, true); - break; - case HEADING: - compass_gauge_set_value(self->compass, val, true); - attitude_indicator_set_heading(self->attitude, val); - break; - case HUD_VALUE_MAX: /*Fall through*/ - default: - break; - } - } -} - -float basic_hud_get(BasicHud *self, HudValue hv) -{ - switch(hv){ - case ALTITUDE: - return tape_gauge_get_value(self->altgroup->altimeter->tape); - break; - case VERTICAL_SPEED: - return sfv_gauge_get_value(SFV_GAUGE(self->altgroup->vsi)); - break; - case AIRSPEED: - return tape_gauge_get_value(self->airspeed->tape); - break; - case PITCH: - return self->attitude->pitch; /*will return the frame's value*/ - break; - case ROLL: - return sfv_gauge_get_value(SFV_GAUGE(self->attitude->rollslip)); - break; - case HEADING: - return sfv_gauge_get_value(SFV_GAUGE(self->compass)); - break; - case SLIP: - return self->attitude->rollslip->slip; - break; - case HUD_VALUE_MAX: /*Fall through*/ - default: - break; - - } - return NAN; -} - -void basic_hud_attitude_changed(BasicHud *self, AttitudeData *newv) -{ - attitude_indicator_set_pitch(self->attitude, newv->pitch, true); - attitude_indicator_set_roll(self->attitude, newv->roll, true); - compass_gauge_set_value(self->compass, newv->heading, true); - attitude_indicator_set_heading(self->attitude, newv->heading); -} - -void basic_hud_dynamics_changed(BasicHud *self, DynamicsData *newv) -{ -// printf("called with airpseed: %f, vertical speed: %f\n", newv->airspeed, newv->vertical_speed*60); - airspeed_indicator_set_value(self->airspeed, newv->airspeed); - /* Convert fps to fpm - * TODO: Document and make units consistent - * */ - alt_group_set_vertical_speed(self->altgroup, newv->vertical_speed * 60); - roll_slip_gauge_set_slip(self->attitude->rollslip, newv->slip_rad * 180.0/M_PI, true); -} - -void basic_hud_location_changed(BasicHud *self, LocationData *newv) -{ - alt_group_set_altitude(self->altgroup, newv->altitude); -} - diff --git a/basic-hud.h b/basic-hud.h deleted file mode 100644 index 64d7371..0000000 --- a/basic-hud.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef BASIC_HUD_H -#define BASIC_HUD_H - -#include "base-gauge.h" -#include "alt-group.h" -#include "attitude-indicator.h" -#include "airspeed-indicator.h" -#include "compass-gauge.h" -#include "data-source.h" - -typedef enum{ - ALTITUDE, - VERTICAL_SPEED, - AIRSPEED, - PITCH, - ROLL, - SLIP, - HEADING, - - HUD_VALUE_MAX -}HudValue; - -enum{ - ALT_GROUP, - SPEED, - COMPASS, - - LOC_MAX -}; - -typedef struct{ - BaseGauge super; - - AltGroup *altgroup; - AirspeedIndicator *airspeed; - AttitudeIndicator *attitude; - CompassGauge *compass; - - SDL_Rect locations[LOC_MAX]; -}BasicHud; - - -BasicHud *basic_hud_new(void); -BasicHud *basic_hud_init(BasicHud *self); - -float basic_hud_get(BasicHud *self, HudValue hv); -void basic_hud_set(BasicHud *self, int nvalues, ...); -void basic_hud_set_values(BasicHud *self, int nvalues, va_list ap); - -void basic_hud_attitude_changed(BasicHud *self, AttitudeData *newv); -void basic_hud_dynamics_changed(BasicHud *self, DynamicsData *newv); -void basic_hud_location_changed(BasicHud *self, LocationData *newv); -#endif /* BASIC_HUD_H */ diff --git a/compass-gauge.c b/compass-gauge.c deleted file mode 100644 index ba5f973..0000000 --- a/compass-gauge.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include - -#include "base-gauge.h" -#include "compass-gauge.h" -#include "resource-manager.h" -#include "sdl-colors.h" -#include "misc.h" -#include "text-gauge.h" -#include "res-dirs.h" - -static void compass_gauge_render(CompassGauge *self, Uint32 dt, RenderContext *ctx); -static void compass_gauge_update_state(CompassGauge *self, Uint32 dt); -static void *compass_gauge_dispose(CompassGauge *self); -static BaseGaugeOps compass_gauge_ops = { - .render = (RenderFunc)compass_gauge_render, - .update_state = (StateUpdateFunc)compass_gauge_update_state, - .dispose = (DisposeFunc)compass_gauge_dispose -}; - - -CompassGauge *compass_gauge_new(void) -{ - CompassGauge *self; - self = calloc(1, sizeof(CompassGauge)); - if(self){ - if(!compass_gauge_init(self)){ - return base_gauge_free(BASE_GAUGE(self)); - } - } - return(self); -} - -CompassGauge *compass_gauge_init(CompassGauge *self) -{ - bool rv; - - rv = generic_layer_init_from_file(&self->outer, IMG_DIR"/compass-outer.png"); - if(!rv){ - printf("Couldn't load compass outer ring\n"); - return NULL; - } - rv = generic_layer_init_from_file(&self->inner, IMG_DIR"/compass-inner.png"); - if(!rv){ - printf("Couldn't load compass inner ring\n"); - return NULL; - } - - self->caption = text_gauge_new("000\x8f", true, 28, 12); - if(!self->caption) - return NULL; - text_gauge_set_color(self->caption, SDL_BLACK, BACKGROUND_COLOR); - self->caption->alignment = HALIGN_CENTER | VALIGN_MIDDLE; - text_gauge_set_static_font(self->caption, - resource_manager_get_static_font(TERMINUS_12, - &SDL_WHITE, - 2, PCF_DIGITS, "°" - ) - ); - - /* TODO: Move me as first operation to ensure that Ops are always - * set when we return NULL so that base_gauge_dispose (called by - * base_gauge_free) can properly dispose any gauge-allocated resources*/ - base_gauge_init(BASE_GAUGE(self), - &compass_gauge_ops, - generic_layer_w(&self->outer), - generic_layer_h(&self->outer) + base_gauge_h(BASE_GAUGE(self->caption)) - ); - - base_gauge_add_child(BASE_GAUGE(self), BASE_GAUGE(self->caption), - (int)SDLExt_RectMidX(&BASE_GAUGE(self)->frame) - - (int)SDLExt_RectMidX(&BASE_GAUGE(self->caption)->frame), - 0 - ); - - self->icenter = (SDL_Point){ - .x = (generic_layer_w(&self->inner) - 1)/2, - .y = (generic_layer_h(&self->inner) - 1)/2, - }; - - self->outer_rect = (SDL_Rect){ - .x = 0, - .y = base_gauge_h(BASE_GAUGE(self->caption)), - .w = generic_layer_w(&self->outer), - .h = generic_layer_h(&self->outer) - }; - - self->inner_rect = (SDL_Rect){ - .x = (generic_layer_w(&self->outer) - 1)/2 - self->icenter.x, - .y = (generic_layer_h(&self->outer) - 1)/2 - self->icenter.y + self->outer_rect.y, - .w = generic_layer_w(&self->inner), - .h = generic_layer_h(&self->inner) - }; - - generic_layer_build_texture(&self->outer); - generic_layer_build_texture(&self->inner); - -#if !USE_SDL_GPU - self->state.rbuffer = SDL_CreateRGBSurfaceWithFormat(0, - generic_layer_w(&self->inner), - generic_layer_h(&self->inner), - 32, SDL_PIXELFORMAT_RGBA32 - ); - self->renderer = SDL_CreateSoftwareRenderer(self->state.rbuffer); - self->texture = SDL_CreateTextureFromSurface(self->renderer, self->inner.canvas); -#endif - return self; -} - -static void *compass_gauge_dispose(CompassGauge *self) -{ - generic_layer_dispose(&self->outer); - generic_layer_dispose(&self->inner); - - return self; -} - -bool compass_gauge_set_value(CompassGauge *self, float value, bool animated) -{ - bool rv = true; - BaseAnimation *animation; - - value = fmod(value, 360.0); - if(value < 0) - value += 360.0; - /*Temp fix for 'goes backwards effet when going from a value - * near 360 to a value after 360 - * */ - animated = false; - return sfv_gauge_set_value(SFV_GAUGE(self), value, animated); -} - -static void compass_gauge_update_state(CompassGauge *self, Uint32 dt) -{ -#if !USE_SDL_GPU - SDL_FillRect(self->state.rbuffer, NULL, 0x00000000); - if(SFV_GAUGE(self)->value != 0){ - SDL_RenderCopyEx(self->renderer, self->texture, - NULL, NULL, - SFV_GAUGE(self)->value * -1.0f, - &self->icenter, SDL_FLIP_NONE - ); - }else{ - SDL_BlitSurface(self->inner.canvas, NULL,self->state.rbuffer, NULL); - } -#endif - text_gauge_set_value_formatn(self->caption, - 4, /*3 digits plus degree sign*/ - "%03d\x8f", (int)SFV_GAUGE(self)->value - ); -} - -static void compass_gauge_render(CompassGauge *self, Uint32 dt, RenderContext *ctx) -{ - base_gauge_blit_layer(BASE_GAUGE(self), ctx, - &self->outer, - NULL, &self->outer_rect); -#if USE_SDL_GPU - base_gauge_blit_rotated_texture(BASE_GAUGE(self), ctx, - self->inner.texture, - NULL, - SFV_GAUGE(self)->value * -1.0f, - &self->icenter, - &self->inner_rect, - NULL); -#else - base_gauge_blit(BASE_GAUGE(self), ctx, self->state.rbuffer, NULL, &self->inner_rect); -#endif -} - diff --git a/compass-gauge.h b/compass-gauge.h deleted file mode 100644 index 0e3438d..0000000 --- a/compass-gauge.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef COMPASS_GAUGE_H -#define COMPASS_GAUGE_H - -#include "sfv-gauge.h" -#include "generic-layer.h" -#include "text-gauge.h" - -typedef struct{ -#if !USE_SDL_GPU - SDL_Surface *rbuffer; /*rotation buffer*/ -#endif -}CompassGaugeState; - -typedef struct{ - SfvGauge super; - - GenericLayer outer; - GenericLayer inner; - - TextGauge *caption; - - SDL_Point icenter; - SDL_Rect inner_rect; - SDL_Rect outer_rect; -#if !USE_SDL_GPU - SDL_Renderer *renderer; - SDL_Texture *texture; -#endif - CompassGaugeState state; -}CompassGauge; - - -CompassGauge *compass_gauge_new(void); -CompassGauge *compass_gauge_init(CompassGauge *self); - -bool compass_gauge_set_value(CompassGauge *self, float value, bool animated); -#endif /* COMPASS_GAUGE_H */ diff --git a/data-source.c b/data-source.c deleted file mode 100644 index 0614ec7..0000000 --- a/data-source.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include - -#include "data-source.h" -#include "misc.h" - -static DataSource *_datasource = NULL; - -/*forward declarations of private functions*/ -static bool get_listener_range(DataType type, uintf8_t *start, uintf8_t *limit); - - -DataSource *data_source_get_instance(void) -{ - return _datasource; -} - -void data_source_set(DataSource *source) -{ - _datasource = source; -} - - -/** - * @brief Allow a single object to register for several events at once. - * - * @param target The object that will receive the event - * @param nevents Number of DataType/ValueListenerFunc couples that follows - * @param ... couples of DataType/ValueListenerFunc - * - * @return The number of successfuly added listeners. A value different from - * @param nevents indicates a failure after the return value nth listener - */ -size_t data_source_add_events_listener(DataSource *self, void *target, - size_t nevents, ...) -{ - va_list args; - int i; - - va_start(args, nevents); - for(i = 0; i < nevents; i++){ - DataType type = va_arg(args, DataType); - ValueListenerFunc func = va_arg(args, ValueListenerFunc); - bool rv = data_source_add_listener(self, type,&(ValueListener){ - .callback = func, - .target = target - }); - if(!rv) break; - } - va_end(args); - return i; -} - -bool data_source_add_listener(DataSource *self, DataType type, ValueListener *listener) -{ - uintf8_t idx, limit; - - self = self ? self : data_source_get_instance(); - - get_listener_range(type, &idx, &limit); - if(self->nlisteners[type] == limit){ - printf( - "Tried to add another location listener while %d limit has been reached." - "Please increment the corresponding listeners limit\n", limit - ); - return false; - } - self->listeners[idx+self->nlisteners[type]] = *listener; - self->nlisteners[type]++; - - return true; -} - - -void data_source_print_listener_stats(DataSource *self) -{ - printf( - "Current number of listeners:\n" - "\tlocation: %zu\n" - "\tattitude: %zu\n" - "\tdynamics: %zu\n" - "\tengine data: %zu\n" - "\troute: %zu\n", - self->nlisteners[LOCATION_DATA], - self->nlisteners[ATTITUDE_DATA], - self->nlisteners[DYNAMICS_DATA], - self->nlisteners[ENGINE_DATA], - self->nlisteners[ROUTE_DATA] - ); -} - -static void data_source_fire_listeners(DataSource *self, DataType type, void *param) -{ - uintf8_t idx, limit; - - self = self ? self : data_source_get_instance(); - - get_listener_range(type, &idx, &limit); - for(int i = idx; i < idx + self->nlisteners[type]; i++){ - self->listeners[i].callback( - self->listeners[i].target, - param - ); - } -} - -void data_source_set_location(DataSource *self, LocationData *location) -{ - self = self ? self : data_source_get_instance(); - - if(location_equals(location, &self->location)) - return; - - data_source_fire_listeners(self, LOCATION_DATA, location); - self->location = *location; -} - -void data_source_set_attitude(DataSource *self, AttitudeData *attitude) -{ - self = self ? self : data_source_get_instance(); - - if(attitude_equals(attitude, &self->attitude)) - return; - - data_source_fire_listeners(self, ATTITUDE_DATA, attitude); - self->attitude = *attitude; -} - -void data_source_set_dynamics(DataSource *self, DynamicsData *dynamics) -{ - self = self ? self : data_source_get_instance(); - - if(dynamics_equals(dynamics, &self->dynamics)) - return; - data_source_fire_listeners(self, DYNAMICS_DATA, dynamics); - self->dynamics = *dynamics; -} - - -void data_source_set_engine_data(DataSource *self, EngineData *engine_data) -{ - self = self ? self : data_source_get_instance(); - - if(engine_data_equals(engine_data, &self->engine_data)) - return; - data_source_fire_listeners(self, ENGINE_DATA, engine_data); - self->engine_data = *engine_data; -} - -void data_source_set_route_data(DataSource *self, RouteData *route_data) -{ - self = self ? self : data_source_get_instance(); - - if(route_data_equals(route_data, &self->route)) - return; - data_source_fire_listeners(self, ROUTE_DATA, route_data); - self->route = *route_data; -} - - -static bool get_listener_range(DataType type, uintf8_t *start, uintf8_t *limit) -{ - switch(type){ - case LOCATION_DATA: - *start = 0; - *limit = *start + MAX_LOCATION_LISTENERS; - return true; - case ATTITUDE_DATA: - *start = MAX_LOCATION_LISTENERS; - *limit = *start + MAX_ATTITUDE_LISTENERS; - return true; - case DYNAMICS_DATA: - *start = MAX_LOCATION_LISTENERS+MAX_ATTITUDE_LISTENERS; - *limit = *start + MAX_DYNAMICS_LISTENERS; - return true; - case ENGINE_DATA: - *start = MAX_LOCATION_LISTENERS+MAX_ATTITUDE_LISTENERS+MAX_DYNAMICS_LISTENERS; - *limit = *start + MAX_ENGINE_DATA_LISTENERS; - return true; - case ROUTE_DATA: - *start = MAX_LOCATION_LISTENERS+MAX_ATTITUDE_LISTENERS - + MAX_DYNAMICS_LISTENERS + MAX_ENGINE_DATA_LISTENERS; - *limit = *start + MAX_ROUTE_DATA_LISTENERS; - return true; - break; - default: - printf("CRIT: %s: bad type, problems ahead!\n",__FUNCTION__); - return 0; - break; - }; -} - diff --git a/data-source.h b/data-source.h deleted file mode 100644 index f4edfb2..0000000 --- a/data-source.h +++ /dev/null @@ -1,189 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef DATA_SOURCE_H -#define DATA_SOURCE_H -#include -#include -#include - -#include "geo-location.h" - -#define MAX_LOCATION_LISTENERS 3 -#define MAX_ATTITUDE_LISTENERS 3 -#define MAX_DYNAMICS_LISTENERS 1 -#define MAX_ENGINE_DATA_LISTENERS 1 -#define MAX_ROUTE_DATA_LISTENERS 2 -#define TOTAL_MAX_LISTENERS \ - MAX_LOCATION_LISTENERS \ - + MAX_ATTITUDE_LISTENERS \ - + MAX_DYNAMICS_LISTENERS \ - + MAX_ENGINE_DATA_LISTENERS \ - + MAX_ROUTE_DATA_LISTENERS - -typedef struct _DataSource DataSource; -typedef bool (*DataSourceFrameFunc)(DataSource *self, uint32_t dt); -typedef DataSource *(*DataSourceDisposeFunc)(DataSource *self); - -typedef struct{ - /** - * @param dt elapsed milliseconds since previous frame - */ - DataSourceFrameFunc frame; - DataSourceDisposeFunc dispose; -}DataSourceOps; - -typedef void (*ValueListenerFunc)(void *self, const void *newvalue); -typedef struct{ - ValueListenerFunc callback; - void *target; -}ValueListener; - -typedef enum{ - LOCATION_DATA, - ATTITUDE_DATA, - DYNAMICS_DATA, - ENGINE_DATA, - ROUTE_DATA, - N_VALUE_TYPES -}DataType; - -typedef struct{ - float roll; - float pitch; - float heading; -}AttitudeData; - -typedef struct{ - float airspeed; //kts - float vertical_speed; //vertical speed //feets per second - float slip_rad; -}DynamicsData; - -typedef struct{ - float rpm; - float fuel_flow; - float fuel_px; - float oil_temp; - float oil_press; - float cht; - float fuel_qty; -}EngineData; - -typedef struct{ - GeoLocation super; - float altitude; -}LocationData; - -typedef struct{ - GeoLocation to; - GeoLocation from; -}RouteData; - -typedef struct _DataSource{ - DataSourceOps *ops; - - LocationData location; - AttitudeData attitude; - DynamicsData dynamics; - EngineData engine_data; - RouteData route; - - /* We want to avoid dynamic allocation for these. - * Thus the adding functio will emit a warning at runtime if the values are - * exceeded to let the developper know that the value should be - * incremented. - * The number of listeners is known at compile-time and won't change at - * runtime - */ - ValueListener listeners[TOTAL_MAX_LISTENERS]; - size_t nlisteners[N_VALUE_TYPES]; - - bool has_fix; -}DataSource; - -#define DATA_SOURCE(self) ((DataSource*)self) - -DataSource *data_source_get_instance(void); -void data_source_set(DataSource *source); - -bool data_source_add_listener(DataSource *self, DataType type, ValueListener *listener); -size_t data_source_add_events_listener(DataSource *self, void *target, - size_t nevents, ...); -void data_source_print_listener_stats(DataSource *self); - -void data_source_set_location(DataSource *self, LocationData *location); -void data_source_set_attitude(DataSource *self, AttitudeData *attitude); -void data_source_set_dynamics(DataSource *self, DynamicsData *dynamics); -void data_source_set_engine_data(DataSource *self, EngineData *engine_data); -void data_source_set_route_data(DataSource *self, RouteData *route_data); - -static inline DataSource *data_source_init(DataSource *self, DataSourceOps *ops) -{ - self->ops = ops; - return self; -} - -static inline DataSource *data_source_dispose(DataSource *self) -{ - if(self->ops->dispose) - return self->ops->dispose(self); - return self; -} - - -static inline bool data_source_frame(DataSource *self, uint32_t dt) -{ - return self->ops->frame(self, dt); -} - -static inline DataSource *data_source_free(DataSource *self) -{ - free(data_source_dispose(self)); - return NULL; -} - -static inline bool location_equals(LocationData *a, LocationData *b) -{ - return (a->super.latitude == b->super.latitude) - && (a->super.longitude == b->super.longitude) - && (a->altitude == b->altitude); -} - -static inline bool attitude_equals(AttitudeData *a, AttitudeData *b) -{ - return (a->roll == b->roll) - && (a->pitch == b->pitch) - && (a->heading == b->heading); -} - -static inline bool dynamics_equals(DynamicsData *a, DynamicsData *b) -{ - return (a->airspeed == b->airspeed) - && (a->vertical_speed == b->vertical_speed) - && (a->slip_rad == b->slip_rad); -} - -static inline bool engine_data_equals(EngineData *a, EngineData *b) -{ - return (a->rpm == b->rpm) - && (a->fuel_flow == b->fuel_flow) - && (a->fuel_px == b->fuel_px) - && (a->oil_temp == b->oil_temp) - && (a->oil_press == b->oil_press) - && (a->cht == b->cht) - && (a->fuel_qty == b->fuel_qty); -} - -static inline bool route_data_equals(RouteData *a, RouteData *b) -{ - return (a->to.latitude == b->to.latitude) - && (a->to.longitude == b->to.longitude) - && (a->from.latitude == b->from.latitude) - && (a->from.longitude == b->from.longitude); -} -#endif /* DATA_SOURCE_H */ diff --git a/dialogs/airport.h b/dialogs/airport.h deleted file mode 100644 index 7c6c194..0000000 --- a/dialogs/airport.h +++ /dev/null @@ -1,10600 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef AIRPORT_H -#define AIRPORT_H -#include - -typedef struct{ - char *code; - char *name; - double latitude; - double longitude; - int elevation; -}Airport; - -static Airport french_airports[] = { - { - .code = "LF0121", - .name = "La Trancliere", - .latitude = 46.0958333333333, - .longitude = 5.28611111111111, - .elevation = 820, - }, - { - .code = "LF0125", - .name = "Lavours", - .latitude = 45.7958333333333, - .longitude = 5.77388888888889, - .elevation = 768, - }, - { - .code = "LF0151", - .name = "Corbonod Seyssel", - .latitude = 45.9613888888889, - .longitude = 5.81805555555556, - .elevation = 1175, - }, - { - .code = "LF0152", - .name = "Crottet Le Bief", - .latitude = 46.285, - .longitude = 4.88611111111111, - .elevation = 597, - }, - { - .code = "LF0153", - .name = "Izenave", - .latitude = 46.0275, - .longitude = 5.52388888888889, - .elevation = 2280, - }, - { - .code = "LF0154", - .name = "Polliat", - .latitude = 46.2561111111111, - .longitude = 5.14944444444444, - .elevation = 718, - }, - { - .code = "LF0157", - .name = "Mionnay", - .latitude = 45.9005555555556, - .longitude = 4.89611111111111, - .elevation = 900, - }, - { - .code = "LF0158", - .name = "Rhone Lavours", - .latitude = 45.8108333333333, - .longitude = 5.78138888888889, - .elevation = 767, - }, - { - .code = "LF0159", - .name = "Montrevel en Bresse", - .latitude = 46.345, - .longitude = 5.14222222222222, - .elevation = 620, - }, - { - .code = "LF0160", - .name = "Tallissieu", - .latitude = 45.8716666666667, - .longitude = 5.72694444444444, - .elevation = 1433, - }, - { - .code = "LF0161", - .name = "Chaneins", - .latitude = 46.1063888888889, - .longitude = 4.85111111111111, - .elevation = 800, - }, - { - .code = "LF0221", - .name = "Azur Ulm", - .latitude = 49.4611111111111, - .longitude = 3.84833333333333, - .elevation = 240, - }, - { - .code = "LF0223", - .name = "Mosloy", - .latitude = 49.1747222222222, - .longitude = 3.15472222222222, - .elevation = 453, - }, - { - .code = "LF0225", - .name = "Ployart", - .latitude = 49.5038888888889, - .longitude = 3.73805555555556, - .elevation = 580, - }, - { - .code = "LF0226", - .name = "Brochot", - .latitude = 48.9766666666667, - .longitude = 3.37333333333333, - .elevation = 574, - }, - { - .code = "LF0253", - .name = "Neuflieux", - .latitude = 49.6111111111111, - .longitude = 3.14861111111111, - .elevation = 195, - }, - { - .code = "LF0256", - .name = "Corbeny ", - .latitude = 49.4575, - .longitude = 3.85444444444444, - .elevation = 230, - }, - { - .code = "LF0257", - .name = "Taillefontaine", - .latitude = 49.3069444444444, - .longitude = 3.06527777777778, - .elevation = 475, - }, - { - .code = "LF0258", - .name = "La Flamengrie", - .latitude = 50.0002777777778, - .longitude = 3.94472222222222, - .elevation = 642, - }, - { - .code = "LF0259", - .name = "Base Ulm du Val de l'Ailette", - .latitude = 49.5675, - .longitude = 3.23027777777778, - .elevation = 184, - }, - { - .code = "LF0324", - .name = "Veauce", - .latitude = 46.1733333333333, - .longitude = 3.05888888888889, - .elevation = 1570, - }, - { - .code = "LF0353", - .name = "Saint Fargeol Les Fougeres", - .latitude = 46.1416666666667, - .longitude = 2.61138888888889, - .elevation = 1706, - }, - { - .code = "LF0354", - .name = "Verneuil en Bourbonnais", - .latitude = 46.36, - .longitude = 3.26833333333333, - .elevation = 885, - }, - { - .code = "LF0355", - .name = "Banelle", - .latitude = 46.1252777777778, - .longitude = 3.28694444444444, - .elevation = 355, - }, - { - .code = "LF0369", - .name = "La Tuiliere", - .latitude = 46.5327777777778, - .longitude = 3.11833333333333, - .elevation = 860, - }, - { - .code = "LF0421", - .name = "Clamensane les 3 Fontaines", - .latitude = 44.314318784384, - .longitude = 6.07152620103625, - .elevation = 2933, - }, - { - .code = "LF0426", - .name = "Thorame Haute Les Serres", - .latitude = 44.1230555555556, - .longitude = 6.56, - .elevation = 6129, - }, - { - .code = "LF0429", - .name = "Sainte Croix sur Verdon", - .latitude = 43.7786111111111, - .longitude = 6.15972222222222, - .elevation = 2190, - }, - { - .code = "LF0430", - .name = "Seyne les Alpes", - .latitude = 44.3419444444444, - .longitude = 6.37277777777778, - .elevation = 3937, - }, - { - .code = "LF0431", - .name = "La Motte du Caire", - .latitude = 44.3227777777778, - .longitude = 6.03138888888889, - .elevation = 2132, - }, - { - .code = "LF0434", - .name = "Thorame Haute Les Serres 2", - .latitude = 44.115, - .longitude = 6.53861111111111, - .elevation = 6398, - }, - { - .code = "LF0451", - .name = "Hippodrome Oraison", - .latitude = 43.9213888888889, - .longitude = 5.90416666666667, - .elevation = 1100, - }, - { - .code = "LF0452", - .name = "Segries", - .latitude = 43.8677777777778, - .longitude = 6.17833333333333, - .elevation = 2657, - }, - { - .code = "LF0453", - .name = "Cruis Mas Des Grailles", - .latitude = 44.0602777777778, - .longitude = 5.85305555555555, - .elevation = 2270, - }, - { - .code = "LF0456", - .name = "Banon", - .latitude = 44.0722222222222, - .longitude = 5.63916666666667, - .elevation = 3723, - }, - { - .code = "LF0458", - .name = "Thorame-Haute Chamatte", - .latitude = 44.1397222222222, - .longitude = 6.54833333333333, - .elevation = 6827, - }, - { - .code = "LF0459", - .name = "Thorame Basse", - .latitude = 44.0769444444445, - .longitude = 6.47361111111111, - .elevation = 3609, - }, - { - .code = "LF0523", - .name = "Glacier Lombard", - .latitude = 45.1083333333333, - .longitude = 6.32222222222222, - .elevation = 10695, - }, - { - .code = "LF0524", - .name = "Grand Terrus", - .latitude = 44.4227777777778, - .longitude = 5.64416666666667, - .elevation = 2871, - }, - { - .code = "LF0538", - .name = "Saint Etienne en Devoluy", - .latitude = 44.6680555555556, - .longitude = 5.90472222222222, - .elevation = 6201, - }, - { - .code = "LF0551", - .name = "Crots", - .latitude = 44.5366666666667, - .longitude = 6.435, - .elevation = 2600, - }, - { - .code = "LF0553", - .name = "Colombe d'Eyguians", - .latitude = 44.365, - .longitude = 5.78666666666667, - .elevation = 2410, - }, - { - .code = "LF0621", - .name = "Isola 2000", - .latitude = 44.1716666666667, - .longitude = 7.16305555555556, - .elevation = 7620, - }, - { - .code = "LF0651", - .name = "Juan Les Pins", - .latitude = 43.5655555555556, - .longitude = 7.1025, - .elevation = 0, - }, - { - .code = "LF0652", - .name = "Cipieres Alpes d'Azur ULM", - .latitude = 43.7791666666667, - .longitude = 6.86305555555556, - .elevation = 3740, - }, - { - .code = "LF0654", - .name = "Valberg", - .latitude = 44.1069444444444, - .longitude = 6.93944444444444, - .elevation = 5680, - }, - { - .code = "LF0723", - .name = "Notre-Dame-des-Neiges-Abbaye", - .latitude = 44.6005555555556, - .longitude = 3.92666666666667, - .elevation = 3760, - }, - { - .code = "LF0725", - .name = "Le Bez", - .latitude = 44.6336111111111, - .longitude = 4.04611111111111, - .elevation = 4320, - }, - { - .code = "LF0753", - .name = "Deyras Saint Victor", - .latitude = 45.0933333333333, - .longitude = 4.70694444444444, - .elevation = 1425, - }, - { - .code = "LF0851", - .name = "Avaux - Les Bourdons ", - .latitude = 49.4805555555556, - .longitude = 4.075, - .elevation = 374, - }, - { - .code = "LF0921", - .name = "Aleu", - .latitude = 42.9002777777778, - .longitude = 1.27527777777778, - .elevation = 3445, - }, - { - .code = "LF0922", - .name = "Artigat - Martin Gu'air", - .latitude = 43.1466666666667, - .longitude = 1.44, - .elevation = 730, - }, - { - .code = "LF0924", - .name = "La Plagne Bouirex", - .latitude = 42.8666666666667, - .longitude = 1.13833333333333, - .elevation = 5249, - }, - { - .code = "LF0925", - .name = "Villeneuve du Latou", - .latitude = 43.2044444444444, - .longitude = 1.41916666666667, - .elevation = 1330, - }, - { - .code = "LF0926", - .name = "Cerizols", - .latitude = 43.1288888888889, - .longitude = 1.06944444444444, - .elevation = 0, - }, - { - .code = "LF0927", - .name = "Troye d'Ariege", - .latitude = 43.02, - .longitude = 1.8775, - .elevation = 1377, - }, - { - .code = "LF0928", - .name = "Ferme de Bon repos - Regat", - .latitude = 42.9838888888889, - .longitude = 1.89361111111111, - .elevation = 1341, - }, - { - .code = "LF0951", - .name = "Sarrat", - .latitude = 43.2086111111111, - .longitude = 1.70861111111111, - .elevation = 846, - }, - { - .code = "LF0952", - .name = "Fabas", - .latitude = 43.1102777777778, - .longitude = 1.11583333333333, - .elevation = 1299, - }, - { - .code = "LF0953", - .name = "Ustou", - .latitude = 42.7813888888889, - .longitude = 1.22583333333333, - .elevation = 5896, - }, - { - .code = "LF0954", - .name = "Erce", - .latitude = 42.8511111111111, - .longitude = 1.29722222222222, - .elevation = 2950, - }, - { - .code = "LF1021", - .name = "Montardoise", - .latitude = 48.4680555555556, - .longitude = 4.19777777777778, - .elevation = 580, - }, - { - .code = "LF1022", - .name = "Ville sur Arce", - .latitude = 48.0883333333333, - .longitude = 4.43583333333333, - .elevation = 910, - }, - { - .code = "LF1054", - .name = "Viapres le petit", - .latitude = 48.5727777777778, - .longitude = 4.03555555555556, - .elevation = 250, - }, - { - .code = "LF1055", - .name = "Romilly", - .latitude = 48.5, - .longitude = 3.75416666666667, - .elevation = 256, - }, - { - .code = "LF1056", - .name = "Amance", - .latitude = 48.3508333333333, - .longitude = 4.505, - .elevation = 430, - }, - { - .code = "LF1123", - .name = "Baraigne", - .latitude = 43.3233333333333, - .longitude = 1.83361111111111, - .elevation = 920, - }, - { - .code = "LF1125", - .name = "Nebias", - .latitude = 42.8916666666667, - .longitude = 2.12361111111111, - .elevation = 1830, - }, - { - .code = "LF1151", - .name = "Fleury d'Aude", - .latitude = 43.2136111111111, - .longitude = 3.13, - .elevation = 100, - }, - { - .code = "LF1153", - .name = "Limoux", - .latitude = 43.0572222222222, - .longitude = 2.22638888888889, - .elevation = 660, - }, - { - .code = "LF1156", - .name = "Ulm Saint Couat", - .latitude = 43.2111111111111, - .longitude = 2.64638888888889, - .elevation = 307, - }, - { - .code = "LF1158", - .name = "Beaugaillard", - .latitude = 43.1786111111111, - .longitude = 1.95166666666667, - .elevation = 930, - }, - { - .code = "LF1159", - .name = "Argeliers", - .latitude = 43.3083333333333, - .longitude = 2.89333333333333, - .elevation = 140, - }, - { - .code = "LF1222", - .name = "La Brousse Golinhac ", - .latitude = 44.5811111111111, - .longitude = 2.59138888888889, - .elevation = 2185, - }, - { - .code = "LF1225", - .name = "Graissac le Faula", - .latitude = 44.7708333333333, - .longitude = 2.78861111111111, - .elevation = 2800, - }, - { - .code = "LF1226", - .name = "Therondels Douzalbats", - .latitude = 44.8930555555556, - .longitude = 2.71805555555556, - .elevation = 3068, - }, - { - .code = "LF1231", - .name = "Villefranche de Panat", - .latitude = 44.0991666666667, - .longitude = 2.69527777777778, - .elevation = 2385, - }, - { - .code = "LF1232", - .name = "Ste Croix", - .latitude = 44.4138888888889, - .longitude = 1.94333333333333, - .elevation = 1128, - }, - { - .code = "LF1233", - .name = "Sarrans Cantoin", - .latitude = 44.8261111111111, - .longitude = 2.84333333333333, - .elevation = 3140, - }, - { - .code = "LF1251", - .name = "Bozouls", - .latitude = 44.4780555555556, - .longitude = 2.74722222222222, - .elevation = 1991, - }, - { - .code = "LF1254", - .name = "Saint Felix de Lunel", - .latitude = 44.5625, - .longitude = 2.54194444444444, - .elevation = 1900, - }, - { - .code = "LF1255", - .name = "Barrage de Pareloup", - .latitude = 44.2077777777778, - .longitude = 2.72277777777778, - .elevation = 2635, - }, - { - .code = "LF1301", - .name = "Martigues-Henri Fabre", - .latitude = 43.4208333333333, - .longitude = 5.07777777777778, - .elevation = 0, - }, - { - .code = "LF1352", - .name = "Jouques Bedes", - .latitude = 43.6613888888889, - .longitude = 5.68694444444444, - .elevation = 1378, - }, - { - .code = "LF1353", - .name = "La Ciotat", - .latitude = 43.1736111111111, - .longitude = 5.64138888888889, - .elevation = 0, - }, - { - .code = "LF1354", - .name = "Meyrargues", - .latitude = 43.6525890394483, - .longitude = 5.52511157141794, - .elevation = 650, - }, - { - .code = "LF1355", - .name = "Marseille Hydro", - .latitude = 43.2991666666667, - .longitude = 5.3475, - .elevation = 0, - }, - { - .code = "LF1422", - .name = "Bonneville la Louvet", - .latitude = 49.2633333333333, - .longitude = 0.371666666666667, - .elevation = 361, - }, - { - .code = "LF1451", - .name = "Courseulles sur Mer", - .latitude = 49.3141666666667, - .longitude = -0.453333333333333, - .elevation = 150, - }, - { - .code = "LF1452", - .name = "La Boissiere", - .latitude = 49.125, - .longitude = 0.1425, - .elevation = 540, - }, - { - .code = "LF1454", - .name = "Rouvres", - .latitude = 49.02, - .longitude = -0.198333333333333, - .elevation = 345, - }, - { - .code = "LF1456", - .name = "Omaha Beach", - .latitude = 49.3530555555556, - .longitude = -0.842777777777778, - .elevation = 203, - }, - { - .code = "LF1457", - .name = "ZTN AIR", - .latitude = 49.0313888888889, - .longitude = 0.0361111111111111, - .elevation = 102, - }, - { - .code = "LF1522", - .name = "Trizac", - .latitude = 45.268333, - .longitude = 2.54805599999997, - .elevation = 3300, - }, - { - .code = "LF1525", - .name = "Polminhac", - .latitude = 44.9427777777778, - .longitude = 2.5775, - .elevation = 2090, - }, - { - .code = "LF1552", - .name = "Le Peuch", - .latitude = 44.9002777777778, - .longitude = 3.10666666666667, - .elevation = 3000, - }, - { - .code = "LF1553", - .name = "Le Bruel", - .latitude = 44.7430555555556, - .longitude = 2.20027777777778, - .elevation = 1427, - }, - { - .code = "LF1625", - .name = "Pillac", - .latitude = 45.3316666666667, - .longitude = 0.184722222222222, - .elevation = 335, - }, - { - .code = "LF1627", - .name = "Saint Maurice", - .latitude = 45.9666666666667, - .longitude = 0.739722222222222, - .elevation = 755, - }, - { - .code = "LF1628", - .name = "Saint Meme Les Carrieres", - .latitude = 45.6327777777778, - .longitude = -0.159722222222222, - .elevation = 82, - }, - { - .code = "LF1629", - .name = "Saint Coutant", - .latitude = 46.0188888888889, - .longitude = 0.433055555555556, - .elevation = 600, - }, - { - .code = "LF1631", - .name = "Le Luquet", - .latitude = 45.6433333333333, - .longitude = 0.331111111111111, - .elevation = 400, - }, - { - .code = "LF1651", - .name = "Aignes et Puyperoux", - .latitude = 45.4616666666667, - .longitude = 0.157777777777778, - .elevation = 619, - }, - { - .code = "LF1652", - .name = "Brettes", - .latitude = 46.0111111111111, - .longitude = 0.0525, - .elevation = 400, - }, - { - .code = "LF1653", - .name = "Saint Ciers", - .latitude = 45.8505555555556, - .longitude = 0.265277777777778, - .elevation = 314, - }, - { - .code = "LF1654", - .name = "Belzagot", - .latitude = 45.3566666666667, - .longitude = 0.109722222222222, - .elevation = 210, - }, - { - .code = "LF1655", - .name = "CHENOMMET", - .latitude = 45.9261111111111, - .longitude = 0.261388888888889, - .elevation = 330, - }, - { - .code = "LF1726", - .name = "Jarnac Champagne", - .latitude = 45.5597222222222, - .longitude = -0.417777777777778, - .elevation = 200, - }, - { - .code = "LF1727", - .name = "Nantille", - .latitude = 45.8455555555556, - .longitude = -0.478333333333333, - .elevation = 134, - }, - { - .code = "LF1751", - .name = "Corme Ecluse", - .latitude = 45.6208333333333, - .longitude = -0.851388888888889, - .elevation = 98, - }, - { - .code = "LF1752", - .name = "Aigrefeuille d'Aunis", - .latitude = 46.1272222222222, - .longitude = -0.951666666666667, - .elevation = 110, - }, - { - .code = "LF1753", - .name = "Le Thou", - .latitude = 46.0861111111111, - .longitude = -0.943611111111111, - .elevation = 89, - }, - { - .code = "LF1755", - .name = "Courcon Eol'Aunis", - .latitude = 46.2483333333333, - .longitude = -0.830277777777778, - .elevation = 39, - }, - { - .code = "LF1756", - .name = "Bourcefranc", - .latitude = 45.8719444444444, - .longitude = -1.13111111111111, - .elevation = 0, - }, - { - .code = "LF1757", - .name = "Arvert", - .latitude = 45.7502777777778, - .longitude = -1.10194444444444, - .elevation = 13, - }, - { - .code = "LF1821", - .name = "Coust Colombiers", - .latitude = 46.6791666666667, - .longitude = 2.57444444444444, - .elevation = 720, - }, - { - .code = "LF1822", - .name = "Guilly", - .latitude = 47.1483333333333, - .longitude = 2.59888888888889, - .elevation = 574, - }, - { - .code = "LF1826", - .name = "Sury en Vaux", - .latitude = 47.3808333333333, - .longitude = 2.7825, - .elevation = 1000, - }, - { - .code = "LF1852", - .name = "Dun sur Auron", - .latitude = 46.8761111111111, - .longitude = 2.50361111111111, - .elevation = 515, - }, - { - .code = "LF1853", - .name = "Sainte Thorette", - .latitude = 47.0758333333333, - .longitude = 2.21388888888889, - .elevation = 400, - }, - { - .code = "LF1854", - .name = "Saint Christophe", - .latitude = 46.5811111111111, - .longitude = 2.40444444444444, - .elevation = 880, - }, - { - .code = "LF1856", - .name = "Jouet sur l'Aubois", - .latitude = 47.0422222222222, - .longitude = 2.995, - .elevation = 640, - }, - { - .code = "LF1921", - .name = "Eyburie", - .latitude = 45.4852777777778, - .longitude = 1.645, - .elevation = 1316, - }, - { - .code = "LF1923", - .name = "Peyrelevade", - .latitude = 45.7077777777778, - .longitude = 2.0325, - .elevation = 2493, - }, - { - .code = "LF1926", - .name = "Lagarde Enval", - .latitude = 45.1772222222222, - .longitude = 1.80277777777778, - .elevation = 1600, - }, - { - .code = "LF1927", - .name = "Troches-Pompadour", - .latitude = 45.4080555555556, - .longitude = 1.42027777777778, - .elevation = 1368, - }, - { - .code = "LF1929", - .name = "Saint Cernin de Larche", - .latitude = 45.1077777777778, - .longitude = 1.41055555555556, - .elevation = 331, - }, - { - .code = "LF1930", - .name = "Varieras", - .latitude = 45.6105555555556, - .longitude = 1.99277777777778, - .elevation = 2755, - }, - { - .code = "LF1951", - .name = "Les Chanseves", - .latitude = 45.09, - .longitude = 1.85527777777778, - .elevation = 1550, - }, - { - .code = "LF1952", - .name = "Lagleygeolle", - .latitude = 45.0802777777778, - .longitude = 1.67333333333333, - .elevation = 1380, - }, - { - .code = "LF1953", - .name = "Perols sur Vezere", - .latitude = 45.5872222222222, - .longitude = 2.01333333333333, - .elevation = 2800, - }, - { - .code = "LF1954", - .name = "Savignoux", - .latitude = 45.0125, - .longitude = 1.78194444444444, - .elevation = 886, - }, - { - .code = "LF2022", - .name = "Cargese", - .latitude = 42.1755555555556, - .longitude = 8.60888888888889, - .elevation = 17, - }, - { - .code = "LF2121", - .name = "Auxey Duresses", - .latitude = 46.9988888888889, - .longitude = 4.735, - .elevation = 1378, - }, - { - .code = "LF2122", - .name = "Chaume et Courchamp", - .latitude = 47.575, - .longitude = 5.35111111111111, - .elevation = 930, - }, - { - .code = "LF2123", - .name = "Dampierre et Flee", - .latitude = 47.4775, - .longitude = 5.35833333333333, - .elevation = 751, - }, - { - .code = "LF2127", - .name = "Chazan", - .latitude = 47.2158333333333, - .longitude = 4.90416666666667, - .elevation = 1516, - }, - { - .code = "LF2132", - .name = "Souhil", - .latitude = 47.9225, - .longitude = 4.76861111111111, - .elevation = 792, - }, - { - .code = "LF2134", - .name = "Recey Le Mont de Lucey", - .latitude = 47.7941666666667, - .longitude = 4.855, - .elevation = 1300, - }, - { - .code = "LF2151", - .name = "Saint Jean de Losne", - .latitude = 47.0736111111111, - .longitude = 5.26611111111111, - .elevation = 600, - }, - { - .code = "LF2161", - .name = "Chateau La Chassagne", - .latitude = 47.309444444444, - .longitude = 4.81944444444457, - .elevation = 1118, - }, - { - .code = "LF2162", - .name = "Saint-Romain", - .latitude = 47.0169444444444, - .longitude = 4.69972222222222, - .elevation = 1850, - }, - { - .code = "LF2163", - .name = "Nantoux", - .latitude = 47.0241666666667, - .longitude = 4.75722222222222, - .elevation = 1138, - }, - { - .code = "LF2164", - .name = "Blanot", - .latitude = 47.1738888888889, - .longitude = 4.23361111111111, - .elevation = 1575, - }, - { - .code = "LF2221", - .name = "Kerfot la Paimpolaise", - .latitude = 48.7238888888889, - .longitude = -3.02694444444444, - .elevation = 308, - }, - { - .code = "LF2321", - .name = "Evaux", - .latitude = 46.17, - .longitude = 2.43083333333333, - .elevation = 1512, - }, - { - .code = "LF2351", - .name = "Le Pommier", - .latitude = 46.1966666666667, - .longitude = 1.45277777777778, - .elevation = 1140, - }, - { - .code = "LF2353", - .name = "Le Pouyollet Lizieres", - .latitude = 46.2125, - .longitude = 1.57222222222222, - .elevation = 1380, - }, - { - .code = "LF2421", - .name = "Augignac", - .latitude = 45.5630555555556, - .longitude = 0.704444444444444, - .elevation = 865, - }, - { - .code = "LF2422", - .name = "Beaumont", - .latitude = 44.7661111111111, - .longitude = 0.724722222222222, - .elevation = 508, - }, - { - .code = "LF2423", - .name = "Condat sur Vezere", - .latitude = 45.1038888888889, - .longitude = 1.215, - .elevation = 499, - }, - { - .code = "LF2424", - .name = "Coursac", - .latitude = 45.110696804337, - .longitude = 0.64083567725288, - .elevation = 730, - }, - { - .code = "LF2426", - .name = "Eyrignac", - .latitude = 44.9430555555556, - .longitude = 1.31194444444444, - .elevation = 820, - }, - { - .code = "LF2428", - .name = "Javerlhac", - .latitude = 45.5538888888889, - .longitude = 0.558611111111111, - .elevation = 633, - }, - { - .code = "LF2430", - .name = "Lalinde", - .latitude = 44.8808333333333, - .longitude = 0.744444444444444, - .elevation = 614, - }, - { - .code = "LF2431", - .name = "Liorac sur Louyre", - .latitude = 44.9188888888889, - .longitude = 0.645555555555556, - .elevation = 518, - }, - { - .code = "LF2432", - .name = "Pressignac Vicq Rebeyrotte", - .latitude = 44.9027777777778, - .longitude = 0.748055555555555, - .elevation = 643, - }, - { - .code = "LF2433", - .name = "La Rochebeaucourt Argentine", - .latitude = 45.4666666666667, - .longitude = 0.3875, - .elevation = 468, - }, - { - .code = "LF2434", - .name = "Saint Crepin Carlucet", - .latitude = 44.9669444444444, - .longitude = 1.25083333333333, - .elevation = 840, - }, - { - .code = "LF2436", - .name = "Saint Julien", - .latitude = 44.7286111111111, - .longitude = 0.446111111111111, - .elevation = 449, - }, - { - .code = "LF2437", - .name = "Le Rigola Bourdeilles", - .latitude = 45.3038888888889, - .longitude = 0.596388888888889, - .elevation = 580, - }, - { - .code = "LF2438", - .name = "Bas Meygnaud Valeuil", - .latitude = 45.3269444444445, - .longitude = 0.636388888888889, - .elevation = 405, - }, - { - .code = "LF2443", - .name = "Peyrillac", - .latitude = 44.8902777777778, - .longitude = 1.41638888888889, - .elevation = 2950, - }, - { - .code = "LF2446", - .name = "Sud-Ouest Aero-Loisirs", - .latitude = 45.4405555555556, - .longitude = 1.22694444444444, - .elevation = 1148, - }, - { - .code = "LF2449", - .name = "Hautefaye", - .latitude = 45.5452777777778, - .longitude = 0.493333333333333, - .elevation = 450, - }, - { - .code = "LF2452", - .name = "Sanet Agonac", - .latitude = 45.2525, - .longitude = 0.763055555555556, - .elevation = 546, - }, - { - .code = "LF2453", - .name = "Ferme Milhac- Oie en Perigord", - .latitude = 45.1133333333333, - .longitude = 0.9225, - .elevation = 754, - }, - { - .code = "LF2454", - .name = "Terrasson le Bos", - .latitude = 45.1344444444444, - .longitude = 1.33666666666667, - .elevation = 292, - }, - { - .code = "LF2458", - .name = "Piste du Tartou", - .latitude = 45.6502777777778, - .longitude = 0.575, - .elevation = 756, - }, - { - .code = "LF2461", - .name = "Galinat Tamnies les Eyzies", - .latitude = 44.9919444444444, - .longitude = 1.14194444444444, - .elevation = 655, - }, - { - .code = "LF2462", - .name = "Plazac", - .latitude = 45.0266666666667, - .longitude = 1.01416666666667, - .elevation = 700, - }, - { - .code = "LF2463", - .name = "Thenac", - .latitude = 44.7452777777778, - .longitude = 0.325555555555556, - .elevation = 328, - }, - { - .code = "LF2465", - .name = "Le Pas de l'Aze", - .latitude = 45.22, - .longitude = 0.478055555555556, - .elevation = 495, - }, - { - .code = "LF2466", - .name = "Clissac", - .latitude = 44.9102777777778, - .longitude = 1.29138888888889, - .elevation = 500, - }, - { - .code = "LF2467", - .name = "Malbec", - .latitude = 45.0077777777778, - .longitude = 1.01611111111111, - .elevation = 850, - }, - { - .code = "LF2468", - .name = "Mauzens et Miremont", - .latitude = 44.9997222222222, - .longitude = 0.906388888888889, - .elevation = 800, - }, - { - .code = "LF2469", - .name = "Campsegret", - .latitude = 44.9611111111111, - .longitude = 0.563888888888889, - .elevation = 567, - }, - { - .code = "LF2521", - .name = "Lanans", - .latitude = 47.3025, - .longitude = 6.45305555555556, - .elevation = 1640, - }, - { - .code = "LF2552", - .name = "Bonnay", - .latitude = 47.3336111111111, - .longitude = 6.03583333333333, - .elevation = 751, - }, - { - .code = "LF2553", - .name = "Fournet Blancheroche", - .latitude = 47.1777777777778, - .longitude = 6.81361111111111, - .elevation = 2874, - }, - { - .code = "LF2554", - .name = "Arc sous Cicon", - .latitude = 47.0458333333333, - .longitude = 6.38888888888889, - .elevation = 2608, - }, - { - .code = "LF2555", - .name = "Athose", - .latitude = 47.0766666666667, - .longitude = 6.28944444444444, - .elevation = 2360, - }, - { - .code = "LF2557", - .name = "La Vrine Paramoteur", - .latitude = 46.9761111111111, - .longitude = 6.33222222222222, - .elevation = 2707, - }, - { - .code = "LF2621", - .name = "Faucon", - .latitude = 44.5369444444444, - .longitude = 5.30861111111111, - .elevation = 3300, - }, - { - .code = "LF2622", - .name = "Bellegarde en Diois", - .latitude = 44.5536111111111, - .longitude = 5.43833333333333, - .elevation = 3378, - }, - { - .code = "LF2623", - .name = "Col de Bacchus", - .latitude = 44.8530555555556, - .longitude = 5.16916666666667, - .elevation = 3200, - }, - { - .code = "LF2624", - .name = "L'Escoulin", - .latitude = 44.8158333333333, - .longitude = 5.22027777777778, - .elevation = 2165, - }, - { - .code = "LF2628", - .name = "Etoile Rhone", - .latitude = 44.83, - .longitude = 4.86888888888889, - .elevation = 377, - }, - { - .code = "LF2629", - .name = "Ratieres Les Allandaines", - .latitude = 45.1661111111111, - .longitude = 4.97916666666667, - .elevation = 886, - }, - { - .code = "LF2651", - .name = "Base ULM Anthony Delluc", - .latitude = 45.0119444444444, - .longitude = 5.08388888888889, - .elevation = 656, - }, - { - .code = "LF2655", - .name = "Saint Martin", - .latitude = 44.5880555555556, - .longitude = 5.54138888888889, - .elevation = 3205, - }, - { - .code = "LF2721", - .name = "Saint Cyr La Campagne", - .latitude = 49.2530555555556, - .longitude = 1.02888888888889, - .elevation = 370, - }, - { - .code = "LF2722", - .name = "Berville sur Mer", - .latitude = 49.4358333333333, - .longitude = 0.363611111111111, - .elevation = 16, - }, - { - .code = "LF2723", - .name = "Breuilpont", - .latitude = 48.96, - .longitude = 1.43833333333333, - .elevation = 312, - }, - { - .code = "LF2751", - .name = "Les Noyers", - .latitude = 49.2597222222222, - .longitude = 1.66138888888889, - .elevation = 328, - }, - { - .code = "LF2752", - .name = "Cesseville Ferme des Moulins", - .latitude = 49.1783333333333, - .longitude = 0.996388888888889, - .elevation = 485, - }, - { - .code = "LF2753", - .name = "Val de Reuil", - .latitude = 49.2813888888889, - .longitude = 1.23138888888889, - .elevation = 33, - }, - { - .code = "LF2822", - .name = "Champrond Le Petit Bois Landry", - .latitude = 48.3938888888889, - .longitude = 1.0575, - .elevation = 853, - }, - { - .code = "LF2823", - .name = "Loulappe", - .latitude = 48.4383333333333, - .longitude = 1.27444444444444, - .elevation = 577, - }, - { - .code = "LF2825", - .name = "Santilly", - .latitude = 48.1588888888889, - .longitude = 1.85333333333333, - .elevation = 425, - }, - { - .code = "LF2827", - .name = "Fontaine Simon", - .latitude = 48.5069444444444, - .longitude = 0.9925, - .elevation = 689, - }, - { - .code = "LF2829", - .name = "Voves Viabon", - .latitude = 48.2111111111111, - .longitude = 1.67333333333333, - .elevation = 476, - }, - { - .code = "LF2830", - .name = "Ecrosnes", - .latitude = 48.5608333333333, - .longitude = 1.73055555555556, - .elevation = 515, - }, - { - .code = "LF2834", - .name = "Les Ailes d'Eure et Loir", - .latitude = 48.5922222222222, - .longitude = 1.5375, - .elevation = 480, - }, - { - .code = "LF2851", - .name = "Houville La Branche", - .latitude = 48.4530555555556, - .longitude = 1.62972222222222, - .elevation = 496, - }, - { - .code = "LF2853", - .name = "Le Gault St Denis", - .latitude = 48.2183333333333, - .longitude = 1.49611111111111, - .elevation = 446, - }, - { - .code = "LF2854", - .name = "La Saussaye", - .latitude = 48.4125, - .longitude = 1.55388888888889, - .elevation = 495, - }, - { - .code = "LF2855", - .name = "La maison des pionniers", - .latitude = 48.8244444444444, - .longitude = 1.58388888888889, - .elevation = 360, - }, - { - .code = "LF2856", - .name = "Le Buternay", - .latitude = 48.6119444444444, - .longitude = 0.841944444444444, - .elevation = 522, - }, - { - .code = "LF2857", - .name = "Paramoteur Paris Ouest", - .latitude = 48.7675, - .longitude = 1.54055555555556, - .elevation = 433, - }, - { - .code = "LF2858", - .name = "club du Houssay", - .latitude = 48.2269444444444, - .longitude = 1.38527777777778, - .elevation = 429, - }, - { - .code = "LF2859", - .name = "Les Ailes d'Horus", - .latitude = 48.4922222222222, - .longitude = 1.76305555555556, - .elevation = 501, - }, - { - .code = "LF2860", - .name = "Plein Ciel Paramoteur", - .latitude = 48.6044444444444, - .longitude = 1.58694444444444, - .elevation = 439, - }, - { - .code = "LF2921", - .name = "Plouarzel", - .latitude = 48.4225, - .longitude = -4.69694444444445, - .elevation = 400, - }, - { - .code = "LF2922", - .name = "Poullaouen Le Stancou", - .latitude = 48.3572222222222, - .longitude = -3.66333333333333, - .elevation = 492, - }, - { - .code = "LF2923", - .name = "Querlarn Plobannalec Lesconi", - .latitude = 47.8186111111111, - .longitude = -4.25027777777778, - .elevation = 49, - }, - { - .code = "LF2925", - .name = "Le Grand Chene", - .latitude = 48.3402777777778, - .longitude = -3.71472222222222, - .elevation = 450, - }, - { - .code = "LF2B24", - .name = "domaine Aliso Rossi", - .latitude = 42.6469444444444, - .longitude = 9.28805555555556, - .elevation = 49, - }, - { - .code = "LF2B25", - .name = "Aleria Padulone", - .latitude = 42.1080555555556, - .longitude = 9.5425, - .elevation = 5, - }, - { - .code = "LF3023", - .name = "Tornac", - .latitude = 44.0122222222222, - .longitude = 3.96333333333333, - .elevation = 690, - }, - { - .code = "LF3025", - .name = "Remoulins", - .latitude = 43.9472222222222, - .longitude = 4.58833333333333, - .elevation = 105, - }, - { - .code = "LF3026", - .name = "Montcalm", - .latitude = 43.5716666666667, - .longitude = 4.30138888888889, - .elevation = 10, - }, - { - .code = "LF3052", - .name = "Saint Victor", - .latitude = 44.0352777777778, - .longitude = 4.47361111111111, - .elevation = 430, - }, - { - .code = "LF3053", - .name = "Le Grand Plantier", - .latitude = 43.8227777777778, - .longitude = 4.12611111111111, - .elevation = 300, - }, - { - .code = "LF3126", - .name = "Sabonneres", - .latitude = 43.4547222222222, - .longitude = 1.07416666666667, - .elevation = 1050, - }, - { - .code = "LF3128", - .name = "Bois de la Pierre", - .latitude = 43.3419444444444, - .longitude = 1.14361111111111, - .elevation = 840, - }, - { - .code = "LF3129", - .name = "Pene de Soulit", - .latitude = 42.7930555555556, - .longitude = 0.4625, - .elevation = 6240, - }, - { - .code = "LF3130", - .name = "Uls", - .latitude = 42.8519444444444, - .longitude = 0.848888888888889, - .elevation = 6568, - }, - { - .code = "LF3131", - .name = "Cap de Barres", - .latitude = 42.8641666666667, - .longitude = 0.516111111111111, - .elevation = 5798, - }, - { - .code = "LF3132", - .name = "Cap de Pouy", - .latitude = 42.7847222222222, - .longitude = 0.545, - .elevation = 5905, - }, - { - .code = "LF3133", - .name = "Honteyde", - .latitude = 42.8361111111111, - .longitude = 0.502777777777778, - .elevation = 6234, - }, - { - .code = "LF3134", - .name = "L'Isle en Dodon", - .latitude = 43.3808333333333, - .longitude = 0.851666666666667, - .elevation = 918, - }, - { - .code = "LF3135", - .name = "Saint Felix Lauragais", - .latitude = 43.4386111111111, - .longitude = 1.90888888888889, - .elevation = 712, - }, - { - .code = "LF3136", - .name = "Gardouch", - .latitude = 43.4016666666667, - .longitude = 1.68638888888889, - .elevation = 564, - }, - { - .code = "LF3137", - .name = "Cier de Riviere", - .latitude = 43.0677777777778, - .longitude = 0.628611111111111, - .elevation = 1312, - }, - { - .code = "LF3138", - .name = "Bacaneres", - .latitude = 42.8380555555556, - .longitude = 0.658611111111111, - .elevation = 6532, - }, - { - .code = "LF3140", - .name = "Villematier", - .latitude = 43.8272222222222, - .longitude = 1.48972222222222, - .elevation = 354, - }, - { - .code = "LF3151", - .name = "Le Fousseret", - .latitude = 43.2688888888889, - .longitude = 1.05388888888889, - .elevation = 820, - }, - { - .code = "LF3153", - .name = "Balesta Nature", - .latitude = 43.1533333333333, - .longitude = 0.995, - .elevation = 1394, - }, - { - .code = "LF3154", - .name = "Labastide St Sernin ", - .latitude = 43.7336111111111, - .longitude = 1.45972222222222, - .elevation = 500, - }, - { - .code = "LF3155", - .name = "Marmouzet ", - .latitude = 43.2455555555556, - .longitude = 1.23166666666667, - .elevation = 1050, - }, - { - .code = "LF3156", - .name = "Le Tucoulet", - .latitude = 43.2011111111111, - .longitude = 0.5475, - .elevation = 1627, - }, - { - .code = "LF3157", - .name = "Le Burgaud", - .latitude = 43.8147222222222, - .longitude = 1.14083333333333, - .elevation = 600, - }, - { - .code = "LF3158", - .name = "Gibel", - .latitude = 43.3013888888889, - .longitude = 1.7025, - .elevation = 980, - }, - { - .code = "LF3159", - .name = "Molas", - .latitude = 43.4166666666667, - .longitude = 0.753611111111111, - .elevation = 862, - }, - { - .code = "LF3160", - .name = "Carbonne", - .latitude = 43.2791666666667, - .longitude = 1.19222222222222, - .elevation = 709, - }, - { - .code = "LF3161", - .name = "Saint Fereol", - .latitude = 43.4369444444444, - .longitude = 2.02555555555556, - .elevation = 1148, - }, - { - .code = "LF3162", - .name = "Cox", - .latitude = 43.7627777777778, - .longitude = 1.05111111111111, - .elevation = 940, - }, - { - .code = "LF3163", - .name = "Girosp", - .latitude = 43.0216666666667, - .longitude = 0.779166666666667, - .elevation = 1870, - }, - { - .code = "LF3221", - .name = "Bretagne d'Armagnac", - .latitude = 43.8922222222222, - .longitude = 0.145555555555556, - .elevation = 419, - }, - { - .code = "LF3225", - .name = "Biran", - .latitude = 43.6775, - .longitude = 0.408611111111111, - .elevation = 669, - }, - { - .code = "LF3226", - .name = "Berdoues", - .latitude = 43.4705555555556, - .longitude = 0.389166666666667, - .elevation = 665, - }, - { - .code = "LF3227", - .name = "Manent Montane", - .latitude = 43.3469444444444, - .longitude = 0.610833333333333, - .elevation = 1001, - }, - { - .code = "LF3228", - .name = "Duffort", - .latitude = 43.3497222222222, - .longitude = 0.412222222222222, - .elevation = 290, - }, - { - .code = "LF3229", - .name = "La Boulouze", - .latitude = 43.4991666666667, - .longitude = 1.01888888888889, - .elevation = 656, - }, - { - .code = "LF3230", - .name = "Saint Elix Theux", - .latitude = 43.4372222222222, - .longitude = 0.454166666666667, - .elevation = 760, - }, - { - .code = "LF3231", - .name = "Isle de Noe", - .latitude = 43.5925, - .longitude = 0.395, - .elevation = 590, - }, - { - .code = "LF3232", - .name = "Idrac Respailles", - .latitude = 43.5119444444444, - .longitude = 0.435277777777778, - .elevation = 775, - }, - { - .code = "LF3233", - .name = "Lectoure Marsolan", - .latitude = 43.9552777777778, - .longitude = 0.521388888888889, - .elevation = 590, - }, - { - .code = "LF3238", - .name = "Simorre le Puntous", - .latitude = 43.4394444444444, - .longitude = 0.746944444444444, - .elevation = 900, - }, - { - .code = "LF3251", - .name = "Maupas", - .latitude = 43.8305555555556, - .longitude = -0.123611111111111, - .elevation = 250, - }, - { - .code = "LF3253", - .name = "Saint Blancard", - .latitude = 43.3355555555556, - .longitude = 0.665, - .elevation = 950, - }, - { - .code = "LF3254", - .name = "Saint Clar", - .latitude = 43.9122222222222, - .longitude = 0.747222222222222, - .elevation = 574, - }, - { - .code = "LF3255", - .name = "Brugnens", - .latitude = 43.8336111111111, - .longitude = 0.731111111111111, - .elevation = 597, - }, - { - .code = "LF3257", - .name = "Montreal du Gers", - .latitude = 43.9436111111111, - .longitude = 0.191944444444444, - .elevation = 301, - }, - { - .code = "LF3259", - .name = "Gelard", - .latitude = 43.5027777777778, - .longitude = 0.195277777777778, - .elevation = 591, - }, - { - .code = "LF3260", - .name = "En Lebe", - .latitude = 43.6683333333333, - .longitude = 0.916388888888889, - .elevation = 590, - }, - { - .code = "LF3261", - .name = "Chelan", - .latitude = 43.3416666666667, - .longitude = 0.531388888888889, - .elevation = 865, - }, - { - .code = "LF3264", - .name = "Bassoues", - .latitude = 43.5783333333333, - .longitude = 0.269444444444444, - .elevation = 600, - }, - { - .code = "LF3265", - .name = "Mauvezin Monplaisir", - .latitude = 43.7366666666667, - .longitude = 0.864444444444444, - .elevation = 510, - }, - { - .code = "LF3266", - .name = "Nauxion", - .latitude = 43.7372222222222, - .longitude = 0.473611111111111, - .elevation = 745, - }, - { - .code = "LF3267", - .name = "Arrouede", - .latitude = 43.3547222222222, - .longitude = 0.58, - .elevation = 1050, - }, - { - .code = "LF3268", - .name = "Gondrin", - .latitude = 43.9069444444444, - .longitude = 0.248888888888889, - .elevation = 540, - }, - { - .code = "LF3269", - .name = "BASE ULM VIELLA", - .latitude = 43.6111111111111, - .longitude = -0.12, - .elevation = 500, - }, - { - .code = "LF3270", - .name = "Monferran Saves ", - .latitude = 43.6019444444444, - .longitude = 0.967777777777778, - .elevation = 984, - }, - { - .code = "LF3321", - .name = "Bazas Cazats", - .latitude = 44.4627777777778, - .longitude = -0.187777777777778, - .elevation = 300, - }, - { - .code = "LF3322", - .name = "Saint Pierre", - .latitude = 44.6672222222222, - .longitude = -0.219722222222222, - .elevation = 158, - }, - { - .code = "LF3323", - .name = "Sainte Foy", - .latitude = 44.6294444444444, - .longitude = -0.156666666666667, - .elevation = 217, - }, - { - .code = "LF3324", - .name = "Cabanac et Villagrains", - .latitude = 44.6141666666667, - .longitude = -0.576388888888889, - .elevation = 192, - }, - { - .code = "LF3327", - .name = "Sainte Helene", - .latitude = 44.9838888888889, - .longitude = -0.907777777777778, - .elevation = 80, - }, - { - .code = "LF3328", - .name = "Le Barp", - .latitude = 44.6088888888889, - .longitude = -0.669444444444444, - .elevation = 230, - }, - { - .code = "LF3351", - .name = "Campin", - .latitude = 44.4363888888889, - .longitude = -0.0219444444444444, - .elevation = 35, - }, - { - .code = "LF3352", - .name = "Arbis", - .latitude = 44.6805555555556, - .longitude = -0.257222222222222, - .elevation = 200, - }, - { - .code = "LF3353", - .name = "Carcans", - .latitude = 45.0538888888889, - .longitude = -1.04027777777778, - .elevation = 60, - }, - { - .code = "LF3354", - .name = "Cestas", - .latitude = 44.7019444444445, - .longitude = -0.785277777777778, - .elevation = 192, - }, - { - .code = "LF3355", - .name = "ulm air estuaire", - .latitude = 45.015, - .longitude = -0.498333333333333, - .elevation = 9, - }, - { - .code = "LF3356", - .name = "Saint Estephe", - .latitude = 45.2361111111111, - .longitude = -0.752222222222222, - .elevation = 20, - }, - { - .code = "LF3357", - .name = "Chateau Venus", - .latitude = 44.6291666666667, - .longitude = -0.376944444444444, - .elevation = 70, - }, - { - .code = "LF3422", - .name = "Limbardier", - .latitude = 43.3255555555556, - .longitude = 3.18611111111111, - .elevation = 105, - }, - { - .code = "LF3423", - .name = "Puisserguier", - .latitude = 43.3991666666667, - .longitude = 3.03388888888889, - .elevation = 606, - }, - { - .code = "LF3424", - .name = "Sauvian", - .latitude = 43.2722222222222, - .longitude = 3.25055555555556, - .elevation = 91, - }, - { - .code = "LF3425", - .name = "Mas Nouguier ", - .latitude = 43.6058333333333, - .longitude = 3.28527777777778, - .elevation = 1214, - }, - { - .code = "LF3461", - .name = "Pignan", - .latitude = 43.5683333333333, - .longitude = 3.75055555555556, - .elevation = 130, - }, - { - .code = "LF3462", - .name = "Saint Drezery", - .latitude = 43.7369444444444, - .longitude = 3.96027777777778, - .elevation = 321, - }, - { - .code = "LF3466", - .name = "ULM LECROS", - .latitude = 43.8797222222222, - .longitude = 3.34638888888889, - .elevation = 2395, - }, - { - .code = "LF3467", - .name = "Les champs blancs", - .latitude = 43.2944444444444, - .longitude = 3.47444444444444, - .elevation = 36, - }, - { - .code = "LF3468", - .name = "Campagne", - .latitude = 43.7927777777778, - .longitude = 4.03666666666667, - .elevation = 177, - }, - { - .code = "LF3469", - .name = "Sete ULM", - .latitude = 43.4, - .longitude = 3.65472222222222, - .elevation = 0, - }, - { - .code = "LF3470", - .name = "Plaine de Lacan", - .latitude = 43.8488888888889, - .longitude = 3.915, - .elevation = 466, - }, - { - .code = "LF3531", - .name = "Moulins le Haut Bois", - .latitude = 48.0016666666667, - .longitude = -1.35222222222222, - .elevation = 200, - }, - { - .code = "LF3533", - .name = "Langon", - .latitude = 47.7641666666667, - .longitude = -1.86138888888889, - .elevation = 295, - }, - { - .code = "LF3551", - .name = "Landean (Fougeres)", - .latitude = 48.4283333333333, - .longitude = -1.16, - .elevation = 541, - }, - { - .code = "LF3552", - .name = "Amanlis Janze", - .latitude = 47.9930555555556, - .longitude = -1.49138888888889, - .elevation = 203, - }, - { - .code = "LF3553", - .name = "Mont Saint Michel", - .latitude = 48.6044444444444, - .longitude = -1.55166666666667, - .elevation = 16, - }, - { - .code = "LF3555", - .name = "La Dominelais ", - .latitude = 47.75, - .longitude = -1.64944444444444, - .elevation = 138, - }, - { - .code = "LF3557", - .name = "La Baillee sous Champ Fleu", - .latitude = 48.1875, - .longitude = -1.49638888888889, - .elevation = 171, - }, - { - .code = "LF3558", - .name = "Queneleuc", - .latitude = 48.0983333333333, - .longitude = -2.07638888888889, - .elevation = 246, - }, - { - .code = "LF3559", - .name = "la cudelais", - .latitude = 48.415, - .longitude = -1.52222222222222, - .elevation = 141, - }, - { - .code = "LF3560", - .name = "Neuville ", - .latitude = 48.3102777777778, - .longitude = -1.58138888888889, - .elevation = 87, - }, - { - .code = "LF3622", - .name = "Saint Benoit du Sault", - .latitude = 46.4535695300358, - .longitude = 1.4043562698364, - .elevation = 770, - }, - { - .code = "LF3623", - .name = "Brandes La Perouille", - .latitude = 46.6908333333333, - .longitude = 1.53027777777778, - .elevation = 535, - }, - { - .code = "LF3624", - .name = "Grange Dieu Levroux", - .latitude = 46.96, - .longitude = 1.66027777777778, - .elevation = 540, - }, - { - .code = "LF3625", - .name = "Vicq sur Nahon Echalier", - .latitude = 47.1108333333333, - .longitude = 1.56361111111111, - .elevation = 500, - }, - { - .code = "LF3627", - .name = "Lourouer Saint Laurent", - .latitude = 46.6397062283013, - .longitude = 2.01445698738098, - .elevation = 660, - }, - { - .code = "LF3628", - .name = "Prissac", - .latitude = 46.5194444444444, - .longitude = 1.31194444444444, - .elevation = 582, - }, - { - .code = "LF3630", - .name = "Le Pavillon", - .latitude = 46.6733333333333, - .longitude = 1.46194444444444, - .elevation = 525, - }, - { - .code = "LF3651", - .name = "Reuilly", - .latitude = 47.0755555555556, - .longitude = 2.02555555555556, - .elevation = 495, - }, - { - .code = "LF3652", - .name = "Villentrois Les Mardelles", - .latitude = 47.17, - .longitude = 1.44444444444444, - .elevation = 413, - }, - { - .code = "LF3721", - .name = "Neuvy le Roi ", - .latitude = 47.5866666666667, - .longitude = 0.628611111111111, - .elevation = 400, - }, - { - .code = "LF3724", - .name = "Orbigny Les Pallis", - .latitude = 47.2205555555556, - .longitude = 1.29388888888889, - .elevation = 528, - }, - { - .code = "LF3730", - .name = "Jacopeau", - .latitude = 47.4183333333333, - .longitude = 0.323611111111111, - .elevation = 285, - }, - { - .code = "LF3732", - .name = "La Palenderie", - .latitude = 47.6277777777778, - .longitude = 0.626944444444445, - .elevation = 410, - }, - { - .code = "LF3733", - .name = "Hippolytaine", - .latitude = 47.0591666666667, - .longitude = 1.14333333333333, - .elevation = 456, - }, - { - .code = "LF3751", - .name = "Bournan", - .latitude = 47.0833333333333, - .longitude = 0.718333333333333, - .elevation = 377, - }, - { - .code = "LF3752", - .name = "Loches", - .latitude = 47.1538888888889, - .longitude = 1.01416666666667, - .elevation = 390, - }, - { - .code = "LF3753", - .name = "Channay sur Lathan", - .latitude = 47.4611111111111, - .longitude = 0.236666666666667, - .elevation = 300, - }, - { - .code = "LF3754", - .name = "Saint Branchs", - .latitude = 47.2211111111111, - .longitude = 0.737777777777778, - .elevation = 300, - }, - { - .code = "LF3755", - .name = "Saint Hippolyte", - .latitude = 47.0613888888889, - .longitude = 1.14416666666667, - .elevation = 423, - }, - { - .code = "LF3759", - .name = "Morand ", - .latitude = 47.5372222222222, - .longitude = 1.01694444444444, - .elevation = 377, - }, - { - .code = "LF3760", - .name = "Ferme de la Braudiere", - .latitude = 47.5622222222222, - .longitude = 0.307222222222222, - .elevation = 256, - }, - { - .code = "LF3761", - .name = "Lemere", - .latitude = 47.0866666666667, - .longitude = 0.343055555555556, - .elevation = 300, - }, - { - .code = "LF3763", - .name = "Brizay", - .latitude = 47.1016666666667, - .longitude = 0.383055555555556, - .elevation = 89, - }, - { - .code = "LF3764", - .name = "La Provenderie", - .latitude = 47.585222222222, - .longitude = 0.554777777777758, - .elevation = 410, - }, - { - .code = "LF3765", - .name = "Les Bardellieres", - .latitude = 47.4980555555556, - .longitude = 0.437777777777778, - .elevation = 360, - }, - { - .code = "LF3767", - .name = "La Cante", - .latitude = 47.0111111111111, - .longitude = 0.671111111111111, - .elevation = 229, - }, - { - .code = "LF3768", - .name = "Chateau de l'Estang", - .latitude = 47.2069444444444, - .longitude = 1.26444444444444, - .elevation = 466, - }, - { - .code = "LF3821", - .name = "Col de Belledonne", - .latitude = 45.1666666666667, - .longitude = 5.98722222222222, - .elevation = 9120, - }, - { - .code = "LF3822", - .name = "Crete de Brouffiers", - .latitude = 45.0377777777778, - .longitude = 5.87944444444445, - .elevation = 7251, - }, - { - .code = "LF3823", - .name = "Dome de la Lauze", - .latitude = 44.9986111111111, - .longitude = 6.24583333333333, - .elevation = 11647, - }, - { - .code = "LF3824", - .name = "Glacier de la Barbaratre", - .latitude = 45.1605555555556, - .longitude = 6.13888888888889, - .elevation = 9669, - }, - { - .code = "LF3825", - .name = "Col de Sarenne", - .latitude = 45.0875, - .longitude = 6.14583333333333, - .elevation = 6500, - }, - { - .code = "LF3826", - .name = "Notre Dame de La Salette", - .latitude = 44.8419444444444, - .longitude = 5.96277777777778, - .elevation = 5184, - }, - { - .code = "LF3828", - .name = "Mens", - .latitude = 44.8055555555556, - .longitude = 5.75361111111111, - .elevation = 2800, - }, - { - .code = "LF3832", - .name = "L'Alpe du Grand Serre", - .latitude = 45.0, - .longitude = 5.83444444444444, - .elevation = 6700, - }, - { - .code = "LF3833", - .name = "Leyrieu", - .latitude = 45.7680555555556, - .longitude = 5.24388888888889, - .elevation = 663, - }, - { - .code = "LF3851", - .name = "Monestier de Clermont Les Verd", - .latitude = 44.9241666666667, - .longitude = 5.61222222222222, - .elevation = 3250, - }, - { - .code = "LF3852", - .name = "Frontonas", - .latitude = 45.6441666666667, - .longitude = 5.1825, - .elevation = 680, - }, - { - .code = "LF3853", - .name = "Saint Vincent de Mercuze", - .latitude = 45.3683333333333, - .longitude = 5.96888888888889, - .elevation = 846, - }, - { - .code = "LF3856", - .name = "Oulles - La Bergerie", - .latitude = 45.0666666666667, - .longitude = 5.96583333333333, - .elevation = 6500, - }, - { - .code = "LF3857", - .name = "Lumbin", - .latitude = 45.3019444444444, - .longitude = 5.91555555555556, - .elevation = 720, - }, - { - .code = "LF3869", - .name = "Crachier", - .latitude = 45.5497222222222, - .longitude = 5.21944444444444, - .elevation = 1463, - }, - { - .code = "LF3870", - .name = "Grand champ", - .latitude = 45.4405555555556, - .longitude = 4.85166666666667, - .elevation = 720, - }, - { - .code = "LF3871", - .name = "Montaud", - .latitude = 45.2583333333333, - .longitude = 5.55416666666667, - .elevation = 2650, - }, - { - .code = "LF3872", - .name = "les Banchets", - .latitude = 45.0025, - .longitude = 6.12611111111111, - .elevation = 5413, - }, - { - .code = "LF3873", - .name = "Base paramoteur Assieu", - .latitude = 45.4022222222222, - .longitude = 4.84111111111111, - .elevation = 797, - }, - { - .code = "LF3874", - .name = "Saint Hilaire du Rosier", - .latitude = 45.0908333333333, - .longitude = 5.23111111111111, - .elevation = 722, - }, - { - .code = "LF3921", - .name = "Lombard", - .latitude = 46.7694444444444, - .longitude = 5.49833333333333, - .elevation = 682, - }, - { - .code = "LF3922", - .name = "Balaiseaux", - .latitude = 46.9686111111111, - .longitude = 5.46972222222222, - .elevation = 699, - }, - { - .code = "LF3923", - .name = "Saint Claude", - .latitude = 46.3847222222222, - .longitude = 5.77027777777778, - .elevation = 2051, - }, - { - .code = "LF3951", - .name = "Doucier", - .latitude = 46.6636111111111, - .longitude = 5.76138888888889, - .elevation = 1735, - }, - { - .code = "LF3953", - .name = "Boissia", - .latitude = 46.5744444444444, - .longitude = 5.71, - .elevation = 1585, - }, - { - .code = "LF3954", - .name = "Vigearde", - .latitude = 47.2075, - .longitude = 5.705, - .elevation = 955, - }, - { - .code = "LF3956", - .name = "Arbois-Ulm", - .latitude = 46.8972222222222, - .longitude = 5.71805555555556, - .elevation = 940, - }, - { - .code = "LF3957", - .name = "aero Sermange", - .latitude = 47.1880555555556, - .longitude = 5.64777777777778, - .elevation = 869, - }, - { - .code = "LF3958", - .name = "Arthenas", - .latitude = 46.5722222222222, - .longitude = 5.53666666666667, - .elevation = 1560, - }, - { - .code = "LF4051", - .name = "Amou", - .latitude = 43.5872222222222, - .longitude = -0.765277777777778, - .elevation = 250, - }, - { - .code = "LF4052", - .name = "Latecoere", - .latitude = 44.3538888888889, - .longitude = -1.16722222222222, - .elevation = 59, - }, - { - .code = "LF4123", - .name = "Souesmes", - .latitude = 47.4483333333333, - .longitude = 2.21083333333333, - .elevation = 443, - }, - { - .code = "LF4124", - .name = "Souge", - .latitude = 47.7625, - .longitude = 0.738888888888889, - .elevation = 203, - }, - { - .code = "LF4125", - .name = "Montrichard", - .latitude = 47.3352777777778, - .longitude = 1.20305555555556, - .elevation = 210, - }, - { - .code = "LF4128", - .name = "Fougeres sur Bievre", - .latitude = 47.4583333333333, - .longitude = 1.36638888888889, - .elevation = 335, - }, - { - .code = "LF4129", - .name = "Cosseneux Vouzon", - .latitude = 47.6025, - .longitude = 2.08666666666667, - .elevation = 394, - }, - { - .code = "LF4130", - .name = "Pontlevoy", - .latitude = 47.3852777777778, - .longitude = 1.21888888888889, - .elevation = 347, - }, - { - .code = "LF4131", - .name = "Vouzon le Rabot", - .latitude = 47.6561111111111, - .longitude = 1.9875, - .elevation = 426, - }, - { - .code = "LF4152", - .name = "Les Chateaux", - .latitude = 47.3333333333333, - .longitude = 1.27583333333333, - .elevation = 239, - }, - { - .code = "LF4153", - .name = "Chauvigny du Perche", - .latitude = 47.9488888888889, - .longitude = 1.06888888888889, - .elevation = 623, - }, - { - .code = "LF4155", - .name = "Chouzy-sur-Cisse", - .latitude = 47.5069444444444, - .longitude = 1.23277777777778, - .elevation = 210, - }, - { - .code = "LF4156", - .name = "Oucques", - .latitude = 47.8266666666667, - .longitude = 1.31861111111111, - .elevation = 419, - }, - { - .code = "LF4157", - .name = "Selles Saint Denis", - .latitude = 47.4, - .longitude = 1.91694444444444, - .elevation = 293, - }, - { - .code = "LF4221", - .name = "Col du Beal", - .latitude = 45.6811111111111, - .longitude = 3.78861111111111, - .elevation = 4825, - }, - { - .code = "LF4222", - .name = "La Jasserie", - .latitude = 45.3902777777778, - .longitude = 4.57805555555556, - .elevation = 4550, - }, - { - .code = "LF4223", - .name = "Montverdun", - .latitude = 45.7044444444444, - .longitude = 4.07472222222222, - .elevation = 1296, - }, - { - .code = "LF4224", - .name = "Precieux", - .latitude = 45.5880555555556, - .longitude = 4.17555555555556, - .elevation = 1200, - }, - { - .code = "LF4225", - .name = "Roanne Mably", - .latitude = 46.0855555555556, - .longitude = 4.08666666666667, - .elevation = 895, - }, - { - .code = "LF4226", - .name = "Cret de Montieux", - .latitude = 45.4638888888889, - .longitude = 4.60777777777778, - .elevation = 2384, - }, - { - .code = "LF4229", - .name = "Maubeu", - .latitude = 45.4933333333333, - .longitude = 4.46388888888889, - .elevation = 1650, - }, - { - .code = "LF4321", - .name = "Mazeyrat", - .latitude = 45.1080555555556, - .longitude = 3.50361111111111, - .elevation = 1700, - }, - { - .code = "LF4323", - .name = "Les Vastres", - .latitude = 44.9852777777778, - .longitude = 4.2675, - .elevation = 3706, - }, - { - .code = "LF4423", - .name = "Saint Brevin les Pins", - .latitude = 47.2713888888889, - .longitude = -2.13027777777778, - .elevation = 10, - }, - { - .code = "LF4451", - .name = "Frossay", - .latitude = 47.2391666666667, - .longitude = -1.87777777777778, - .elevation = 10, - }, - { - .code = "LF4452", - .name = "La Planche", - .latitude = 47.0277777777778, - .longitude = -1.43444444444444, - .elevation = 105, - }, - { - .code = "LF4453", - .name = "Nantes Heric", - .latitude = 47.3858333333333, - .longitude = -1.63555555555556, - .elevation = 110, - }, - { - .code = "LF4454", - .name = "Le Quilloux", - .latitude = 47.5994444444444, - .longitude = -1.91472222222222, - .elevation = 120, - }, - { - .code = "LF4455", - .name = "La Possardiere", - .latitude = 46.9644444444444, - .longitude = -1.70333333333333, - .elevation = 65, - }, - { - .code = "LF4456", - .name = "les Moisans", - .latitude = 47.2761111111111, - .longitude = -2.09694444444444, - .elevation = 10, - }, - { - .code = "LF4457", - .name = "Campbon La Bertheliere", - .latitude = 47.4208333333333, - .longitude = -2.01194444444444, - .elevation = 146, - }, - { - .code = "LF4524", - .name = "Ligny", - .latitude = 47.7055555555556, - .longitude = 1.77833333333333, - .elevation = 371, - }, - { - .code = "LF4525", - .name = "La Selle en Hermoy", - .latitude = 48.0161111111111, - .longitude = 2.89972222222222, - .elevation = 440, - }, - { - .code = "LF4552", - .name = "Saint Benoit sur Loire", - .latitude = 47.7916666666667, - .longitude = 2.33555555555556, - .elevation = 367, - }, - { - .code = "LF4553", - .name = "Beaugency", - .latitude = 47.7494444444444, - .longitude = 1.57888888888889, - .elevation = 370, - }, - { - .code = "LF4554", - .name = "Beaulieu sur Loire", - .latitude = 47.5575, - .longitude = 2.82555555555556, - .elevation = 443, - }, - { - .code = "LF4555", - .name = "Mardie", - .latitude = 47.9036111111111, - .longitude = 2.06777777777778, - .elevation = 435, - }, - { - .code = "LF4556", - .name = "Marsainvilliers", - .latitude = 48.2216666666667, - .longitude = 2.26111111111111, - .elevation = 416, - }, - { - .code = "LF4557", - .name = "Villemoutier", - .latitude = 47.9702777777778, - .longitude = 2.57361111111111, - .elevation = 328, - }, - { - .code = "LF4558", - .name = "Cravant les Lilas", - .latitude = 47.8366666666667, - .longitude = 1.61777777777778, - .elevation = 377, - }, - { - .code = "LF4559", - .name = "Egry", - .latitude = 48.1063888888889, - .longitude = 2.44805555555556, - .elevation = 361, - }, - { - .code = "LF4560", - .name = "La Rosetaine", - .latitude = 48.1283333333333, - .longitude = 2.93722222222222, - .elevation = 429, - }, - { - .code = "LF4561", - .name = "Les Avant Gardes", - .latitude = 47.8130555555556, - .longitude = 2.23527777777778, - .elevation = 350, - }, - { - .code = "LF4562", - .name = "St Germain", - .latitude = 47.9583333333333, - .longitude = 2.84333333333333, - .elevation = 450, - }, - { - .code = "LF4563", - .name = "Mezieres lez Clery", - .latitude = 47.8108333333333, - .longitude = 1.84083333333333, - .elevation = 344, - }, - { - .code = "LF4564", - .name = "AIR et ESPACE", - .latitude = 48.0419444444444, - .longitude = 3.07611111111111, - .elevation = 540, - }, - { - .code = "LF4565", - .name = "ULM LA CAVE", - .latitude = 47.8722222222222, - .longitude = 2.45444444444444, - .elevation = 410, - }, - { - .code = "LF4621", - .name = "Calviac", - .latitude = 44.9277777777778, - .longitude = 2.06805555555556, - .elevation = 2100, - }, - { - .code = "LF4623", - .name = "Lacave Le Frau", - .latitude = 44.8416666666667, - .longitude = 1.58916666666667, - .elevation = 980, - }, - { - .code = "LF4624", - .name = "Loupiac", - .latitude = 44.8313888888889, - .longitude = 1.47472222222222, - .elevation = 895, - }, - { - .code = "LF4627", - .name = "Saint Medard de Presque", - .latitude = 44.8430555555556, - .longitude = 1.83111111111111, - .elevation = 1246, - }, - { - .code = "LF4628", - .name = "Montaigu de Quercy Valprionde", - .latitude = 44.365, - .longitude = 1.09222222222222, - .elevation = 883, - }, - { - .code = "LF4629", - .name = "Cabrerets", - .latitude = 44.5141666666667, - .longitude = 1.5925, - .elevation = 1177, - }, - { - .code = "LF4630", - .name = "Bigues Carlucet", - .latitude = 44.7441666666667, - .longitude = 1.61833333333333, - .elevation = 1045, - }, - { - .code = "LF4631", - .name = "Vers", - .latitude = 44.4863888888889, - .longitude = 1.53305555555556, - .elevation = 981, - }, - { - .code = "LF4632", - .name = "Montfaucon", - .latitude = 44.6911111111111, - .longitude = 1.61916666666667, - .elevation = 1148, - }, - { - .code = "LF4651", - .name = "Cezac", - .latitude = 44.3475, - .longitude = 1.34777777777778, - .elevation = 902, - }, - { - .code = "LF4652", - .name = "les landes", - .latitude = 44.9442250793634, - .longitude = 1.64698967933657, - .elevation = 700, - }, - { - .code = "LF4722", - .name = "Castillonnes ", - .latitude = 44.6986111111111, - .longitude = 0.638888888888889, - .elevation = 394, - }, - { - .code = "LF4723", - .name = "Condezaygues", - .latitude = 44.479722, - .longitude = 0.916098371688804, - .elevation = 0, - }, - { - .code = "LF4724", - .name = "Montpezat d'Agenais", - .latitude = 44.3641666666667, - .longitude = 0.491388888888889, - .elevation = 120, - }, - { - .code = "LF4725", - .name = "Sembas", - .latitude = 44.3375, - .longitude = 0.649444444444444, - .elevation = 787, - }, - { - .code = "LF4726", - .name = "Tremons", - .latitude = 44.4080555555556, - .longitude = 0.890833333333333, - .elevation = 341, - }, - { - .code = "LF4729", - .name = "Saumont Gentieu", - .latitude = 44.1116666666667, - .longitude = 0.466111111111111, - .elevation = 410, - }, - { - .code = "LF4730", - .name = "Claude Vayssiere", - .latitude = 44.5991666666667, - .longitude = 0.341388888888889, - .elevation = 249, - }, - { - .code = "LF4732", - .name = "Clairac", - .latitude = 44.3611111111111, - .longitude = 0.403888888888889, - .elevation = 98, - }, - { - .code = "LF4733", - .name = "Lamourache Nord", - .latitude = 44.6211111111111, - .longitude = 0.193611111111111, - .elevation = 364, - }, - { - .code = "LF4735", - .name = "Lavardac", - .latitude = 44.1708333333333, - .longitude = 0.308611111111111, - .elevation = 180, - }, - { - .code = "LF4736", - .name = "Levignac de Guyenne", - .latitude = 44.6194444444444, - .longitude = 0.231388888888889, - .elevation = 213, - }, - { - .code = "LF4737", - .name = "St Jean de Duras", - .latitude = 44.7080555555556, - .longitude = 0.296944444444444, - .elevation = 145, - }, - { - .code = "LF4738", - .name = "Villeton", - .latitude = 44.3569444444444, - .longitude = 0.286111111111111, - .elevation = 85, - }, - { - .code = "LF4751", - .name = "Fourques", - .latitude = 44.4675, - .longitude = 0.158333333333333, - .elevation = 70, - }, - { - .code = "LF4752", - .name = "Segalas", - .latitude = 44.5913888888889, - .longitude = 0.556944444444444, - .elevation = 436, - }, - { - .code = "LF4753", - .name = "Caudecoste", - .latitude = 44.1055555555556, - .longitude = 0.724722222222222, - .elevation = 323, - }, - { - .code = "LF4754", - .name = "Fauillet", - .latitude = 44.4194444444444, - .longitude = 0.295, - .elevation = 100, - }, - { - .code = "LF4755", - .name = "Mascar", - .latitude = 44.6491666666667, - .longitude = 0.818888888888889, - .elevation = 300, - }, - { - .code = "LF4756", - .name = "Bouglon", - .latitude = 44.4013888888889, - .longitude = 0.110833333333333, - .elevation = 246, - }, - { - .code = "LF4825", - .name = "Fenestres", - .latitude = 44.8441666666667, - .longitude = 3.18805555555556, - .elevation = 3610, - }, - { - .code = "LF4861", - .name = "La Canourgue Conques", - .latitude = 44.4152018104989, - .longitude = 3.28463368249517, - .elevation = 2920, - }, - { - .code = "LF4862", - .name = "Ribennes La Cheminade", - .latitude = 44.6586111111111, - .longitude = 3.34166666666667, - .elevation = 3550, - }, - { - .code = "LF4863", - .name = "Saint Martin de Boubeaux", - .latitude = 44.2118167104827, - .longitude = 3.91310224533074, - .elevation = 1624, - }, - { - .code = "LF4923", - .name = "Saint Sigismond", - .latitude = 47.4394444444444, - .longitude = -0.935833333333333, - .elevation = 243, - }, - { - .code = "LF4925", - .name = "Soucelles", - .latitude = 47.5802777777778, - .longitude = -0.412222222222222, - .elevation = 170, - }, - { - .code = "LF4946", - .name = "Soulaire", - .latitude = 47.5655555555556, - .longitude = -0.549722222222222, - .elevation = 148, - }, - { - .code = "LF4954", - .name = "St Macaire du bois", - .latitude = 47.1263888888889, - .longitude = -0.281388888888889, - .elevation = 170, - }, - { - .code = "LF4955", - .name = "Valanjou", - .latitude = 47.2244444444444, - .longitude = -0.568333333333333, - .elevation = 262, - }, - { - .code = "LF4956", - .name = "Coutures", - .latitude = 47.3661111111111, - .longitude = -0.330555555555556, - .elevation = 100, - }, - { - .code = "LF4957", - .name = "Jumelles", - .latitude = 47.4355555555556, - .longitude = -0.0966666666666667, - .elevation = 130, - }, - { - .code = "LF4958", - .name = "Chesnaie ULM", - .latitude = 47.3394444444444, - .longitude = -0.925, - .elevation = 380, - }, - { - .code = "LF5021", - .name = "Dragey", - .latitude = 48.7052777777778, - .longitude = -1.49388888888889, - .elevation = 147, - }, - { - .code = "LF5022", - .name = "Portbail", - .latitude = 49.3352777777778, - .longitude = -1.71388888888889, - .elevation = 49, - }, - { - .code = "LF5122", - .name = "Servon Melzicourt", - .latitude = 49.205, - .longitude = 4.83083333333333, - .elevation = 410, - }, - { - .code = "LF5123", - .name = "Courtisols les Houches", - .latitude = 48.9952777777778, - .longitude = 4.49666666666667, - .elevation = 492, - }, - { - .code = "LF5124", - .name = "Reims Concept ULM", - .latitude = 49.2047222222222, - .longitude = 3.73333333333333, - .elevation = 557, - }, - { - .code = "LF5152", - .name = "Bouzy", - .latitude = 49.0822222222222, - .longitude = 4.13666666666667, - .elevation = 360, - }, - { - .code = "LF5154", - .name = "Lac du Der", - .latitude = 48.5666666666667, - .longitude = 4.73, - .elevation = 436, - }, - { - .code = "LF5155", - .name = "Champagne Vol Libre", - .latitude = 48.9361111111111, - .longitude = 4.06166666666667, - .elevation = 335, - }, - { - .code = "LF5156", - .name = "Epoye ULM Reims Concept ULM", - .latitude = 49.2772222222222, - .longitude = 4.24055555555556, - .elevation = 328, - }, - { - .code = "LF5224", - .name = "Harricourt la Gonio", - .latitude = 48.2802777777778, - .longitude = 4.91444444444444, - .elevation = 1214, - }, - { - .code = "LF5225", - .name = "Laville aux Bois", - .latitude = 48.0927777777778, - .longitude = 5.20194444444444, - .elevation = 1227, - }, - { - .code = "LF5252", - .name = "les ailes du der", - .latitude = 48.4358333333333, - .longitude = 4.85194444444444, - .elevation = 561, - }, - { - .code = "LF5321", - .name = "Andouille le Tertre picard", - .latitude = 48.1772222222222, - .longitude = -0.850277777777778, - .elevation = 410, - }, - { - .code = "LF5322", - .name = "La Rogerie", - .latitude = 48.3116666666667, - .longitude = -0.535277777777778, - .elevation = 420, - }, - { - .code = "LF5323", - .name = "La Bazouge de Chemere", - .latitude = 48.0130555555556, - .longitude = -0.494166666666667, - .elevation = 308, - }, - { - .code = "LF5324", - .name = "Beausoleil", - .latitude = 47.7775, - .longitude = -0.551111111111111, - .elevation = 236, - }, - { - .code = "LF5325", - .name = "Courcite", - .latitude = 48.29, - .longitude = -0.259166666666667, - .elevation = 787, - }, - { - .code = "LF5351", - .name = "Aron Les Ecottays", - .latitude = 48.2830555555556, - .longitude = -0.515833333333333, - .elevation = 426, - }, - { - .code = "LF5421", - .name = "Mont sur Meurthe", - .latitude = 48.5425, - .longitude = 6.44166666666667, - .elevation = 814, - }, - { - .code = "LF5422", - .name = "Villerupt Micheville", - .latitude = 49.4852777777778, - .longitude = 5.91777777777778, - .elevation = 1305, - }, - { - .code = "LF5423", - .name = "Herbeviller", - .latitude = 48.5561111111111, - .longitude = 6.76888888888889, - .elevation = 860, - }, - { - .code = "LF5451", - .name = "Hoeville", - .latitude = 48.715, - .longitude = 6.43861111111111, - .elevation = 1004, - }, - { - .code = "LF5453", - .name = "Grand Couronne", - .latitude = 48.7661111111111, - .longitude = 6.22111111111111, - .elevation = 1250, - }, - { - .code = "LF5454", - .name = "Laloeuf", - .latitude = 48.4633333333333, - .longitude = 6.02416666666667, - .elevation = 1000, - }, - { - .code = "LF5521", - .name = "Cornieville Geville", - .latitude = 48.7638888888889, - .longitude = 5.69555555555556, - .elevation = 904, - }, - { - .code = "LF5523", - .name = "Chassey Beaupre", - .latitude = 48.4538888888889, - .longitude = 5.44555555555556, - .elevation = 1143, - }, - { - .code = "LF5524", - .name = "Beauclair", - .latitude = 49.4611111111111, - .longitude = 5.10888888888889, - .elevation = 600, - }, - { - .code = "LF5525", - .name = "Fains Veel", - .latitude = 48.78, - .longitude = 5.11055555555556, - .elevation = 827, - }, - { - .code = "LF5526", - .name = "Montmedy Marville", - .latitude = 49.4569444444444, - .longitude = 5.41138888888889, - .elevation = 909, - }, - { - .code = "LF5551", - .name = "Geville", - .latitude = 48.7688888888889, - .longitude = 5.68472222222222, - .elevation = 1115, - }, - { - .code = "LF5552", - .name = "Billy-sous-Mangiennes", - .latitude = 49.3252777777778, - .longitude = 5.60972222222222, - .elevation = 895, - }, - { - .code = "LF5553", - .name = "Mad'In Ulm", - .latitude = 48.9441666666667, - .longitude = 5.70222222222222, - .elevation = 768, - }, - { - .code = "LF5554", - .name = "La Bertaucourt", - .latitude = 49.0733333333333, - .longitude = 5.75166666666667, - .elevation = 669, - }, - { - .code = "LF5653", - .name = "La Bochet", - .latitude = 47.5316666666667, - .longitude = -2.11444444444444, - .elevation = 144, - }, - { - .code = "LF5654", - .name = "Quily", - .latitude = 47.8833333333333, - .longitude = -2.48694444444444, - .elevation = 436, - }, - { - .code = "LF5657", - .name = "Courant d'ailes", - .latitude = 47.5780555555556, - .longitude = -2.64916666666667, - .elevation = 40, - }, - { - .code = "LF5710", - .name = "Bambi Air Club", - .latitude = 49.1161111111111, - .longitude = 6.60777777777778, - .elevation = 1320, - }, - { - .code = "LF5721", - .name = "Denting", - .latitude = 49.188889, - .longitude = 6.555556, - .elevation = 0, - }, - { - .code = "LF5722", - .name = "Fresnes", - .latitude = 48.8566666666667, - .longitude = 6.435, - .elevation = 958, - }, - { - .code = "LF5723", - .name = "Saint Avold", - .latitude = 49.1022222222222, - .longitude = 6.735, - .elevation = 1010, - }, - { - .code = "LF5726", - .name = "Bining", - .latitude = 49.0416666666667, - .longitude = 7.24222222222222, - .elevation = 1200, - }, - { - .code = "LF5728", - .name = "Falstrof", - .latitude = 49.3925, - .longitude = 6.54388888888889, - .elevation = 951, - }, - { - .code = "LF5730", - .name = "Gros Rederching", - .latitude = 49.0625, - .longitude = 7.23972222222222, - .elevation = 1132, - }, - { - .code = "LF5751", - .name = "L'oiseau Blanc Achen", - .latitude = 49.0475, - .longitude = 7.16166666666667, - .elevation = 980, - }, - { - .code = "LF5752", - .name = "Hargarten aux Mines", - .latitude = 49.2194444444444, - .longitude = 6.58694444444444, - .elevation = 1050, - }, - { - .code = "LF5753", - .name = "Remeling", - .latitude = 49.4119444444444, - .longitude = 6.47694444444444, - .elevation = 1017, - }, - { - .code = "LF5754", - .name = "Folschviller", - .latitude = 49.0744444444444, - .longitude = 6.66638888888889, - .elevation = 1160, - }, - { - .code = "LF5755", - .name = "Zoufftgen", - .latitude = 49.4491666666667, - .longitude = 6.12555555555555, - .elevation = 750, - }, - { - .code = "LF5757", - .name = "Cappel", - .latitude = 49.0736111111111, - .longitude = 6.84111111111111, - .elevation = 985, - }, - { - .code = "LF5758", - .name = "Mosailes", - .latitude = 49.0358333333333, - .longitude = 6.86416666666667, - .elevation = 836, - }, - { - .code = "LF5759", - .name = "Les ailes de Rohrbach", - .latitude = 49.0452777777778, - .longitude = 7.25444444444444, - .elevation = 1223, - }, - { - .code = "LF5760", - .name = "Cann'Air", - .latitude = 49.3447222222222, - .longitude = 6.28777777777778, - .elevation = 852, - }, - { - .code = "LF5761", - .name = "Arc-En-Ciel Paramoteurs", - .latitude = 49.3763888888889, - .longitude = 6.03527777777778, - .elevation = 1214, - }, - { - .code = "LF5762", - .name = "Langatte ULM", - .latitude = 48.7488888888889, - .longitude = 6.95944444444444, - .elevation = 850, - }, - { - .code = "LF5763", - .name = "Langatte paramoteur", - .latitude = 48.7494444444444, - .longitude = 6.95944444444444, - .elevation = 850, - }, - { - .code = "LF5764", - .name = "Saint Georges", - .latitude = 48.6519444444444, - .longitude = 6.93555555555556, - .elevation = 1050, - }, - { - .code = "LF5765", - .name = "ULM HIGHLANDER", - .latitude = 49.1216666666667, - .longitude = 6.99166666666667, - .elevation = 1033, - }, - { - .code = "LF5825", - .name = "Ville Langy", - .latitude = 46.9475, - .longitude = 3.49027777777778, - .elevation = 902, - }, - { - .code = "LF5826", - .name = "Champlemy Varzy", - .latitude = 47.2908333333333, - .longitude = 3.36333333333333, - .elevation = 1020, - }, - { - .code = "LF5827", - .name = "Luzy", - .latitude = 46.7791666666667, - .longitude = 3.98333333333333, - .elevation = 920, - }, - { - .code = "LF5852", - .name = "La Collancelle", - .latitude = 47.1911111111111, - .longitude = 3.64416666666667, - .elevation = 985, - }, - { - .code = "LF5854", - .name = "Beard", - .latitude = 46.8647222222222, - .longitude = 3.33583333333333, - .elevation = 770, - }, - { - .code = "LF5855", - .name = "Le Charmois", - .latitude = 47.0197222222222, - .longitude = 3.77944444444444, - .elevation = 919, - }, - { - .code = "LF5930", - .name = "Herlies", - .latitude = 50.5852777777778, - .longitude = 2.83888888888889, - .elevation = 102, - }, - { - .code = "LF5953", - .name = "Ferme de Bonavis", - .latitude = 50.0841666666667, - .longitude = 3.19611111111111, - .elevation = 403, - }, - { - .code = "LF6021", - .name = "Bonneuil en Valois", - .latitude = 49.2780555555556, - .longitude = 2.99055555555556, - .elevation = 394, - }, - { - .code = "LF6023", - .name = "Fretoy le Chateau", - .latitude = 49.6675, - .longitude = 2.96805555555556, - .elevation = 270, - }, - { - .code = "LF6025", - .name = "St Thibault - Menantissard", - .latitude = 49.6933333333333, - .longitude = 1.81222222222222, - .elevation = 660, - }, - { - .code = "LF6026", - .name = "Flavacourt", - .latitude = 49.3508333333333, - .longitude = 1.81333333333333, - .elevation = 456, - }, - { - .code = "LF6051", - .name = "Mouy", - .latitude = 49.3147222222222, - .longitude = 2.30138888888889, - .elevation = 371, - }, - { - .code = "LF6151", - .name = "Val Preaux", - .latitude = 48.320035912179, - .longitude = 0.717565322753899, - .elevation = 360, - }, - { - .code = "LF6152", - .name = "Saint Germain de la Coudre", - .latitude = 48.3005555555556, - .longitude = 0.581111111111111, - .elevation = 520, - }, - { - .code = "LF6153", - .name = "Le Cerisier", - .latitude = 48.4858333333333, - .longitude = -0.773611111111111, - .elevation = 630, - }, - { - .code = "LF6224", - .name = "Frevent", - .latitude = 50.2780555555556, - .longitude = 2.30277777777778, - .elevation = 438, - }, - { - .code = "LF6251", - .name = "Boulogne sur Mer", - .latitude = 50.6952777777778, - .longitude = 1.56861111111111, - .elevation = 190, - }, - { - .code = "LF6252", - .name = "Verchocq", - .latitude = 50.5416666666667, - .longitude = 2.035, - .elevation = 574, - }, - { - .code = "LF6321", - .name = "Saint Priest des Champs", - .latitude = 45.9588888888889, - .longitude = 2.74888888888889, - .elevation = 2250, - }, - { - .code = "LF6322", - .name = "La Banne d'Ordanche", - .latitude = 45.630556, - .longitude = 2.79166699999996, - .elevation = 4820, - }, - { - .code = "LF6323", - .name = "La Rochette Sauvagnat", - .latitude = 45.7680555555556, - .longitude = 2.60277777777778, - .elevation = 2350, - }, - { - .code = "LF6324", - .name = "Charbonnieres les Vieilles", - .latitude = 46.0136111111111, - .longitude = 3.02388888888889, - .elevation = 2067, - }, - { - .code = "LF6326", - .name = "Jayet Gannat", - .latitude = 46.0713888888889, - .longitude = 3.19944444444444, - .elevation = 1171, - }, - { - .code = "LF6329", - .name = "Aubiat / Sardon ", - .latitude = 45.9797222222222, - .longitude = 3.2275, - .elevation = 1160, - }, - { - .code = "LF6330", - .name = "St Gal sur Sioule Les Tabarias", - .latitude = 46.1108333333333, - .longitude = 2.99194444444444, - .elevation = 1640, - }, - { - .code = "LF6352", - .name = "Grand Prouilhat - Maringues", - .latitude = 45.9338888888889, - .longitude = 3.31666666666667, - .elevation = 1010, - }, - { - .code = "LF6353", - .name = "Thinlat Billom", - .latitude = 45.7297222222222, - .longitude = 3.29944444444444, - .elevation = 1170, - }, - { - .code = "LF6354", - .name = "Verneugheol", - .latitude = 45.7680555555556, - .longitude = 2.50388888888889, - .elevation = 2395, - }, - { - .code = "LF6355", - .name = "Le Vernet Ste Marguerite", - .latitude = 45.6113888888889, - .longitude = 2.94583333333333, - .elevation = 3428, - }, - { - .code = "LF6356", - .name = "Saint-Julien Sancy", - .latitude = 45.6608333333333, - .longitude = 2.67444444444444, - .elevation = 3140, - }, - { - .code = "LF6357", - .name = "Bort l'Etang", - .latitude = 45.7952777777778, - .longitude = 3.43638888888889, - .elevation = 1286, - }, - { - .code = "LF6421", - .name = "Asson", - .latitude = 43.1691666666667, - .longitude = -0.258333333333333, - .elevation = 853, - }, - { - .code = "LF6422", - .name = "Boeil Bezing", - .latitude = 43.245, - .longitude = -0.213333333333333, - .elevation = 1000, - }, - { - .code = "LF6424", - .name = "Came", - .latitude = 43.5102777777778, - .longitude = -1.10388888888889, - .elevation = 223, - }, - { - .code = "LF6425", - .name = "Gurmencon", - .latitude = 43.1597222222222, - .longitude = -0.606666666666667, - .elevation = 860, - }, - { - .code = "LF6427", - .name = "Maslacq", - .latitude = 43.4466666666667, - .longitude = -0.695, - .elevation = 256, - }, - { - .code = "LF6428", - .name = "Escary Aramits", - .latitude = 43.1205555555556, - .longitude = -0.741388888888889, - .elevation = 1050, - }, - { - .code = "LF6429", - .name = "Claracq Villa les Palmiers", - .latitude = 43.4941666666667, - .longitude = -0.289722222222222, - .elevation = 787, - }, - { - .code = "LF6431", - .name = "Navarrenx", - .latitude = 43.3405555555556, - .longitude = -0.710277777777778, - .elevation = 876, - }, - { - .code = "LF6432", - .name = "Ozenx Montrestrucq", - .latitude = 43.4338888888889, - .longitude = -0.8, - .elevation = 295, - }, - { - .code = "LF6451", - .name = "Andoins", - .latitude = 43.2975, - .longitude = -0.236111111111111, - .elevation = 919, - }, - { - .code = "LF6452", - .name = "Sames ", - .latitude = 43.5380555555556, - .longitude = -1.18277777777778, - .elevation = 7, - }, - { - .code = "LF6454", - .name = "Malaussanne", - .latitude = 43.5686111111111, - .longitude = -0.475555555555556, - .elevation = 490, - }, - { - .code = "LF6455", - .name = "Ponson Dessus", - .latitude = 43.2952777777778, - .longitude = -0.0644444444444444, - .elevation = 1280, - }, - { - .code = "LF6456", - .name = "Sevignacq", - .latitude = 43.4480555555556, - .longitude = -0.281388888888889, - .elevation = 650, - }, - { - .code = "LF6457", - .name = "Saint Pee sur Nivelle", - .latitude = 43.3388888888889, - .longitude = -1.52944444444444, - .elevation = 302, - }, - { - .code = "LF6521", - .name = "Cabaliros", - .latitude = 42.9525, - .longitude = -0.133333333333333, - .elevation = 5724, - }, - { - .code = "LF6523", - .name = "Coumely", - .latitude = 42.7625, - .longitude = 0.0222222222222222, - .elevation = 6568, - }, - { - .code = "LF6524", - .name = "Ferrere Batmale", - .latitude = 42.8883333333333, - .longitude = 0.498888888888889, - .elevation = 5749, - }, - { - .code = "LF6525", - .name = "La Serre d'Aulon", - .latitude = 42.8361111111111, - .longitude = 0.272222222222222, - .elevation = 6562, - }, - { - .code = "LF6526", - .name = "Quatre Veziaux", - .latitude = 42.8922222222222, - .longitude = 0.299722222222222, - .elevation = 5643, - }, - { - .code = "LF6527", - .name = "Artigues", - .latitude = 43.0719444444444, - .longitude = -0.00333333333333333, - .elevation = 2550, - }, - { - .code = "LF6528", - .name = "Castillon de la Laquette", - .latitude = 42.8955555555556, - .longitude = 0.100555555555556, - .elevation = 5413, - }, - { - .code = "LF6529", - .name = "Hautacam", - .latitude = 42.9925, - .longitude = -0.0119444444444444, - .elevation = 5512, - }, - { - .code = "LF6530", - .name = "Sadournin", - .latitude = 43.3261111111111, - .longitude = 0.416666666666667, - .elevation = 918, - }, - { - .code = "LF6532", - .name = "Sauveterre", - .latitude = 43.4744444444444, - .longitude = 0.0783333333333333, - .elevation = 587, - }, - { - .code = "LF6534", - .name = "Sarriac Bigorre", - .latitude = 43.3825, - .longitude = 0.134166666666667, - .elevation = 718, - }, - { - .code = "LF6536", - .name = "Vallon des Bergons", - .latitude = 43.0197222222222, - .longitude = -0.178055555555556, - .elevation = 3445, - }, - { - .code = "LF6538", - .name = "Aneres", - .latitude = 43.0811111111111, - .longitude = 0.465555555555556, - .elevation = 1700, - }, - { - .code = "LF6539", - .name = "Labatut Riviere", - .latitude = 43.5211111111111, - .longitude = 0.0347222222222222, - .elevation = 534, - }, - { - .code = "LF6540", - .name = "Larreule", - .latitude = 43.4413888888889, - .longitude = 0.04, - .elevation = 606, - }, - { - .code = "LF6551", - .name = "Luquet", - .latitude = 43.2419444444444, - .longitude = -0.1175, - .elevation = 1345, - }, - { - .code = "LF6552", - .name = "Rabastens de Bigorre", - .latitude = 43.3777777777778, - .longitude = 0.161944444444444, - .elevation = 650, - }, - { - .code = "LF6553", - .name = "Vic en Bigorre", - .latitude = 43.3933333333333, - .longitude = 0.101666666666667, - .elevation = 705, - }, - { - .code = "LF6554", - .name = "Fontrailles", - .latitude = 43.3463888888889, - .longitude = 0.359444444444444, - .elevation = 900, - }, - { - .code = "LF6555", - .name = "Plateau de Monhaillat", - .latitude = 42.9113888888889, - .longitude = 0.127777777777778, - .elevation = 6312, - }, - { - .code = "LF6621", - .name = "Coste del Palm", - .latitude = 42.6083333333333, - .longitude = 2.01111111111111, - .elevation = 7710, - }, - { - .code = "LF6622", - .name = "Col de la Marrano", - .latitude = 42.6625, - .longitude = 2.16666666666667, - .elevation = 6562, - }, - { - .code = "LF6623", - .name = "Mont Llaret Pic d'Aude", - .latitude = 42.575, - .longitude = 2.03888888888889, - .elevation = 7628, - }, - { - .code = "LF6624", - .name = "Clos de Legua", - .latitude = 42.6541666666667, - .longitude = 2.03888888888889, - .elevation = 7874, - }, - { - .code = "LF6625", - .name = "Hippopotame", - .latitude = 42.4777777777778, - .longitude = 2.04722222222222, - .elevation = 4921, - }, - { - .code = "LF6626", - .name = "Mont Llaret Roc d'Aude", - .latitude = 42.5805555555556, - .longitude = 2.025, - .elevation = 7710, - }, - { - .code = "LF6627", - .name = "Plateau de la Calme", - .latitude = 42.5305555555556, - .longitude = 2.00416666666667, - .elevation = 6988, - }, - { - .code = "LF6628", - .name = "Perpignan la Salanque", - .latitude = 42.7980555555556, - .longitude = 3.00166666666667, - .elevation = 30, - }, - { - .code = "LF6631", - .name = "Corneilla de la Riviere", - .latitude = 42.6908333333333, - .longitude = 2.73027777777778, - .elevation = 230, - }, - { - .code = "LF6632", - .name = "Saint Genis", - .latitude = 42.5463888888889, - .longitude = 2.90833333333333, - .elevation = 150, - }, - { - .code = "LF6651", - .name = "Torreilles", - .latitude = 42.7475, - .longitude = 3.01611111111111, - .elevation = 10, - }, - { - .code = "LF6652", - .name = "Saint Paul de Fenouillet", - .latitude = 42.8205555555556, - .longitude = 2.49638888888889, - .elevation = 860, - }, - { - .code = "LF6654", - .name = "Llupia", - .latitude = 42.6238888888889, - .longitude = 2.78055555555556, - .elevation = 292, - }, - { - .code = "LF6655", - .name = "Saint Jean Pla de Corts", - .latitude = 42.5197222222222, - .longitude = 2.81055555555556, - .elevation = 270, - }, - { - .code = "LF6656", - .name = "Montescot", - .latitude = 42.6116666666667, - .longitude = 2.93888888888889, - .elevation = 55, - }, - { - .code = "LF6658", - .name = "Llauro", - .latitude = 42.5502777777778, - .longitude = 2.73083333333333, - .elevation = 1411, - }, - { - .code = "LF6659", - .name = "La Salanque Latecoere", - .latitude = 42.8166666666667, - .longitude = 3.0, - .elevation = 0, - }, - { - .code = "LF6715", - .name = "Club Ulm Kogenheim", - .latitude = 48.3230555555556, - .longitude = 7.53472222222222, - .elevation = 528, - }, - { - .code = "LF6721", - .name = "Albe - Val de Ville", - .latitude = 48.3491666666667, - .longitude = 7.32972222222222, - .elevation = 1247, - }, - { - .code = "LF6723", - .name = "Salmbach", - .latitude = 48.9680555555556, - .longitude = 8.07083333333333, - .elevation = 508, - }, - { - .code = "LF6724", - .name = "Wissembourg", - .latitude = 48.9925, - .longitude = 7.97583333333333, - .elevation = 574, - }, - { - .code = "LF6751", - .name = "Batzendorf", - .latitude = 48.8030555555556, - .longitude = 7.72666666666667, - .elevation = 560, - }, - { - .code = "LF6752", - .name = "Trimbach", - .latitude = 48.9380555555556, - .longitude = 8.00777777777778, - .elevation = 574, - }, - { - .code = "LF6754", - .name = "Envol Ulm Alsace", - .latitude = 48.1511111111111, - .longitude = 7.53694444444444, - .elevation = 576, - }, - { - .code = "LF6755", - .name = "Hanau-Airport-Schillersdorf", - .latitude = 48.8708333333333, - .longitude = 7.51694444444444, - .elevation = 676, - }, - { - .code = "LF6757", - .name = "Les Cigognes d'Epfig", - .latitude = 48.3394444444444, - .longitude = 7.47222222222222, - .elevation = 173, - }, - { - .code = "LF6821", - .name = "Masevaux", - .latitude = 47.8041666666667, - .longitude = 6.94638888888889, - .elevation = 1500, - }, - { - .code = "LF6822", - .name = "Vieux Ferrette", - .latitude = 47.5158333333333, - .longitude = 7.30694444444444, - .elevation = 1499, - }, - { - .code = "LF6851", - .name = "Valdieu Lutran", - .latitude = 47.6222222222222, - .longitude = 7.04583333333333, - .elevation = 1132, - }, - { - .code = "LF6852", - .name = "Soppe", - .latitude = 47.7255555555556, - .longitude = 7.09694444444444, - .elevation = 1099, - }, - { - .code = "LF6951", - .name = "Saint Jean d'Ardieres", - .latitude = 46.1294444444444, - .longitude = 4.74277777777778, - .elevation = 610, - }, - { - .code = "LF6953", - .name = "Le Parasoir", - .latitude = 46.0319444444444, - .longitude = 4.55583333333333, - .elevation = 2110, - }, - { - .code = "LF6954", - .name = "Base de Bibost", - .latitude = 45.7983333333333, - .longitude = 4.56138888888889, - .elevation = 400, - }, - { - .code = "LF7021", - .name = "Bucey les Gy", - .latitude = 47.415, - .longitude = 5.87138888888889, - .elevation = 1260, - }, - { - .code = "LF7022", - .name = "Francourt", - .latitude = 47.655, - .longitude = 5.73888888888889, - .elevation = 869, - }, - { - .code = "LF7023", - .name = "Saulnot", - .latitude = 47.5677777777778, - .longitude = 6.64472222222222, - .elevation = 1269, - }, - { - .code = "LF7025", - .name = "Tincey", - .latitude = 47.6063888888889, - .longitude = 5.78583333333333, - .elevation = 764, - }, - { - .code = "LF7026", - .name = "Arc les Gray", - .latitude = 47.4755555555556, - .longitude = 5.56916666666667, - .elevation = 718, - }, - { - .code = "LF7027", - .name = "Lambrey", - .latitude = 47.7677777777778, - .longitude = 5.93888888888889, - .elevation = 820, - }, - { - .code = "LF7028", - .name = "Venisey", - .latitude = 47.8344444444444, - .longitude = 5.99888888888889, - .elevation = 804, - }, - { - .code = "LF7029", - .name = "Senoncourt", - .latitude = 47.8322222222222, - .longitude = 6.05305555555555, - .elevation = 778, - }, - { - .code = "LF7030", - .name = "Bay", - .latitude = 47.3013888888889, - .longitude = 5.70416666666667, - .elevation = 709, - }, - { - .code = "LF7031", - .name = "Jasney", - .latitude = 47.8827777777778, - .longitude = 6.17, - .elevation = 919, - }, - { - .code = "LF7032", - .name = "La Malachere", - .latitude = 47.4483333333333, - .longitude = 6.07027777777778, - .elevation = 0, - }, - { - .code = "LF7033", - .name = "Gevigney", - .latitude = 47.7969444444444, - .longitude = 5.91305555555556, - .elevation = 720, - }, - { - .code = "LF7034", - .name = "Lacs de Bonnal", - .latitude = 47.5177777777778, - .longitude = 6.36388888888889, - .elevation = 816, - }, - { - .code = "LF7121", - .name = "Sagy", - .latitude = 46.6155555555556, - .longitude = 5.35277777777778, - .elevation = 640, - }, - { - .code = "LF7124", - .name = "Le Creusot Le Gros Chaillot", - .latitude = 46.8166666666667, - .longitude = 4.40138888888889, - .elevation = 1530, - }, - { - .code = "LF7151", - .name = "La Clayette", - .latitude = 46.3027777777778, - .longitude = 4.29722222222222, - .elevation = 1230, - }, - { - .code = "LF7152", - .name = "Peronne Moulin Chevraut", - .latitude = 46.4330555555556, - .longitude = 4.80166666666667, - .elevation = 755, - }, - { - .code = "LF7153", - .name = "Brancion", - .latitude = 46.54, - .longitude = 4.79222222222222, - .elevation = 1310, - }, - { - .code = "LF7228", - .name = "Piace", - .latitude = 48.2711111111111, - .longitude = 0.103888888888889, - .elevation = 305, - }, - { - .code = "LF7229", - .name = "Crosmieres", - .latitude = 47.7511111111111, - .longitude = -0.1475, - .elevation = 190, - }, - { - .code = "LF7252", - .name = "Commerveil", - .latitude = 48.3155555555556, - .longitude = 0.355, - .elevation = 361, - }, - { - .code = "LF7253", - .name = "Saint Pierre de Cheville ", - .latitude = 47.6333333333333, - .longitude = 0.452222222222222, - .elevation = 160, - }, - { - .code = "LF7256", - .name = "Saint Cosme en Vairais", - .latitude = 48.2619444444444, - .longitude = 0.422222222222217, - .elevation = 250, - }, - { - .code = "LF7258", - .name = "Asse le Riboul", - .latitude = 48.1952777777778, - .longitude = 0.0994444444444444, - .elevation = 300, - }, - { - .code = "LF7259", - .name = "Sceaux sur Huisne", - .latitude = 48.1125, - .longitude = 0.604166666666667, - .elevation = 289, - }, - { - .code = "LF7322", - .name = "Glacier de l'Etendard", - .latitude = 45.1625, - .longitude = 6.16666666666667, - .elevation = 9514, - }, - { - .code = "LF7324", - .name = "Glacier de la Grande Motte", - .latitude = 45.425, - .longitude = 6.89444444444444, - .elevation = 9564, - }, - { - .code = "LF7325", - .name = "La Toviere", - .latitude = 45.4655555555556, - .longitude = 6.93416666666667, - .elevation = 7350, - }, - { - .code = "LF7327", - .name = "Val Thorens Alti", - .latitude = 45.2819444444444, - .longitude = 6.57361111111111, - .elevation = 8100, - }, - { - .code = "LF7328", - .name = "Valmorel", - .latitude = 45.4416666666667, - .longitude = 6.41805555555556, - .elevation = 6332, - }, - { - .code = "LF7329", - .name = "Vaugellaz", - .latitude = 45.6069444444444, - .longitude = 6.70944444444444, - .elevation = 6627, - }, - { - .code = "LF7331", - .name = "Praz Sauge et Pre Vernay", - .latitude = 45.1888888888889, - .longitude = 6.25305555555556, - .elevation = 5950, - }, - { - .code = "LF7332", - .name = "Valloire Bonnenuit", - .latitude = 45.1211111111111, - .longitude = 6.41944444444445, - .elevation = 5600, - }, - { - .code = "LF7333", - .name = "Vers le col du Palet", - .latitude = 45.4505555555556, - .longitude = 6.88333333333333, - .elevation = 8005, - }, - { - .code = "LF7340", - .name = "Chanaz", - .latitude = 45.8188888888889, - .longitude = 5.79, - .elevation = 764, - }, - { - .code = "LF7351", - .name = "Yenne", - .latitude = 45.7133333333333, - .longitude = 5.77694444444444, - .elevation = 750, - }, - { - .code = "LF7421", - .name = "Col de Cenise", - .latitude = 46.0208333333333, - .longitude = 6.45, - .elevation = 5656, - }, - { - .code = "LF7422", - .name = "Glacier d'Argentiere", - .latitude = 45.9416666666667, - .longitude = 7.0, - .elevation = 9350, - }, - { - .code = "LF7423", - .name = "Glacier de Talefre", - .latitude = 45.9083333333333, - .longitude = 6.98333333333333, - .elevation = 9121, - }, - { - .code = "LF7424", - .name = "Glacier du Dome du Gouter", - .latitude = 45.8455555555556, - .longitude = 6.85027777777778, - .elevation = 13940, - }, - { - .code = "LF7425", - .name = "Glacier du Tacul", - .latitude = 45.8916666666667, - .longitude = 6.93722222222222, - .elevation = 7380, - }, - { - .code = "LF7426", - .name = "Glacier du Tour", - .latitude = 46.0, - .longitude = 7.0, - .elevation = 10170, - }, - { - .code = "LF7427", - .name = "Morzine Avoriaz", - .latitude = 46.1966666666667, - .longitude = 6.75972222222222, - .elevation = 5709, - }, - { - .code = "LF7430", - .name = "Saint Roch Mayeres", - .latitude = 45.95, - .longitude = 6.58611111111111, - .elevation = 5118, - }, - { - .code = "LF7431", - .name = "Thollon les Memises", - .latitude = 46.3966666666667, - .longitude = 6.71666666666667, - .elevation = 2996, - }, - { - .code = "LF7469", - .name = "Habere Poche", - .latitude = 46.2719444444444, - .longitude = 6.46388888888889, - .elevation = 3652, - }, - { - .code = "LF7470", - .name = "Cervens", - .latitude = 46.2930555555556, - .longitude = 6.44666666666667, - .elevation = 2034, - }, - { - .code = "LF7621", - .name = "Lammerville", - .latitude = 49.8055555555556, - .longitude = 0.973333333333333, - .elevation = 328, - }, - { - .code = "LF7653", - .name = "Pavilly", - .latitude = 49.6011111111111, - .longitude = 0.9875, - .elevation = 499, - }, - { - .code = "LF7654", - .name = "Bolleville", - .latitude = 49.6005555555556, - .longitude = 0.5525, - .elevation = 443, - }, - { - .code = "LF7655", - .name = "Le Mont Dole", - .latitude = 49.8936111111111, - .longitude = 1.57916666666667, - .elevation = 450, - }, - { - .code = "LF7752", - .name = "Mondreville", - .latitude = 48.1686111111111, - .longitude = 2.59777777777778, - .elevation = 351, - }, - { - .code = "LF7753", - .name = "Bray sur Seine", - .latitude = 48.4319444444444, - .longitude = 3.27305555555556, - .elevation = 180, - }, - { - .code = "LF7754", - .name = "Orgenoy", - .latitude = 48.4941666666667, - .longitude = 2.57638888888889, - .elevation = 262, - }, - { - .code = "LF7756", - .name = "Bazoches les Bray", - .latitude = 48.383888888889, - .longitude = 3.19888888888886, - .elevation = 196, - }, - { - .code = "LF7757", - .name = "Aeronel", - .latitude = 48.6786111111111, - .longitude = 2.87694444444444, - .elevation = 340, - }, - { - .code = "LF7852", - .name = "La Fontaine au Berger", - .latitude = 48.5822222222222, - .longitude = 1.72888888888889, - .elevation = 476, - }, - { - .code = "LF7853", - .name = "Buisson Defleuri", - .latitude = 48.8755555555556, - .longitude = 1.79388888888889, - .elevation = 380, - }, - { - .code = "LF7854", - .name = "La Ferme des Pres", - .latitude = 48.8277777777778, - .longitude = 1.79055555555556, - .elevation = 296, - }, - { - .code = "LF7921", - .name = "Gourge Les Grippeaux", - .latitude = 46.6955555555556, - .longitude = -0.161111111111111, - .elevation = 456, - }, - { - .code = "LF7922", - .name = "Chenay", - .latitude = 46.3466666666667, - .longitude = -0.0155555555555556, - .elevation = 435, - }, - { - .code = "LF7925", - .name = "Saint Amand sur Sevre", - .latitude = 46.9013888888889, - .longitude = -0.802777777777778, - .elevation = 607, - }, - { - .code = "LF7926", - .name = "Verrines sous Celles La Jonche", - .latitude = 46.2263888888889, - .longitude = -0.203611111111111, - .elevation = 360, - }, - { - .code = "LF7951", - .name = "Usseau", - .latitude = 46.175, - .longitude = -0.609722222222222, - .elevation = 115, - }, - { - .code = "LF7952", - .name = "Secondigny", - .latitude = 46.6369444444444, - .longitude = -0.463611111111111, - .elevation = 710, - }, - { - .code = "LF7953", - .name = "Le Grand Moire", - .latitude = 46.8588888888889, - .longitude = -0.181944444444444, - .elevation = 336, - }, - { - .code = "LF8021", - .name = "La Boisselle", - .latitude = 50.0163888888889, - .longitude = 2.68861111111111, - .elevation = 279, - }, - { - .code = "LF8022", - .name = "Jumel", - .latitude = 49.7580555555556, - .longitude = 2.30305555555556, - .elevation = 413, - }, - { - .code = "LF8051", - .name = "Loeuilly", - .latitude = 49.7655555555556, - .longitude = 2.21527777777778, - .elevation = 502, - }, - { - .code = "LF8052", - .name = "Poix de Picardie", - .latitude = 49.7802777777778, - .longitude = 2.00194444444444, - .elevation = 0, - }, - { - .code = "LF8053", - .name = " Marquivillers", - .latitude = 49.6733333333333, - .longitude = 2.68416666666667, - .elevation = 360, - }, - { - .code = "LF8123", - .name = "Saint Affrique les Montagnes", - .latitude = 43.5447222222222, - .longitude = 2.21138888888889, - .elevation = 590, - }, - { - .code = "LF8151", - .name = "L'Isle sur Tarn - Saint Martin", - .latitude = 43.8569444444444, - .longitude = 1.82083333333333, - .elevation = 394, - }, - { - .code = "LF8153", - .name = "La Ramiere", - .latitude = 43.7475, - .longitude = 1.81555555555556, - .elevation = 420, - }, - { - .code = "LF8154", - .name = "Saint Lieux les Lavaur", - .latitude = 43.7613888888889, - .longitude = 1.74111111111111, - .elevation = 400, - }, - { - .code = "LF8155", - .name = "Coufouleux", - .latitude = 43.8016666666667, - .longitude = 1.71861111111111, - .elevation = 406, - }, - { - .code = "LF8156", - .name = "Albi Castelvert", - .latitude = 43.83, - .longitude = 2.12111111111111, - .elevation = 800, - }, - { - .code = "LF8157", - .name = "Bouscatel ", - .latitude = 43.7280555555556, - .longitude = 2.39444444444444, - .elevation = 1919, - }, - { - .code = "LF8159", - .name = "Roquemaure", - .latitude = 43.8216666666667, - .longitude = 1.60527777777778, - .elevation = 630, - }, - { - .code = "LF8160", - .name = "Rivieres", - .latitude = 43.9016666666667, - .longitude = 1.97194444444444, - .elevation = 489, - }, - { - .code = "LF8222", - .name = "Beaumont de Lomagne", - .latitude = 43.8763888888889, - .longitude = 0.983888888888889, - .elevation = 338, - }, - { - .code = "LF8223", - .name = "Bouloc", - .latitude = 44.3077777777778, - .longitude = 1.08055555555556, - .elevation = 745, - }, - { - .code = "LF8225", - .name = "Caussade Septfonds", - .latitude = 44.18, - .longitude = 1.59722222222222, - .elevation = 644, - }, - { - .code = "LF8226", - .name = "Caylus", - .latitude = 44.2225, - .longitude = 1.7325, - .elevation = 1035, - }, - { - .code = "LF8228", - .name = "Montaigu de Quercy Couloussac", - .latitude = 44.3641666666667, - .longitude = 1.08722222222222, - .elevation = 882, - }, - { - .code = "LF8233", - .name = "Pommevic", - .latitude = 44.0841666666667, - .longitude = 0.925833333333333, - .elevation = 226, - }, - { - .code = "LF8251", - .name = "Dunes - Aerodrome Leon Lemarti", - .latitude = 44.1077777777778, - .longitude = 0.775, - .elevation = 236, - }, - { - .code = "LF8252", - .name = "Maubec Solomiac", - .latitude = 43.7883333333333, - .longitude = 0.911388888888889, - .elevation = 575, - }, - { - .code = "LF8253", - .name = "Leguille", - .latitude = 43.9644444444444, - .longitude = 1.55527777777778, - .elevation = 432, - }, - { - .code = "LF8254", - .name = "Les Gardios Negrepelisse", - .latitude = 44.0808333333333, - .longitude = 1.50083333333333, - .elevation = 328, - }, - { - .code = "LF8255", - .name = "Banadets", - .latitude = 44.0483333333333, - .longitude = 1.28333333333333, - .elevation = 280, - }, - { - .code = "LF8256", - .name = "Montbartier", - .latitude = 43.8997222222222, - .longitude = 1.27583333333333, - .elevation = 420, - }, - { - .code = "LF8257", - .name = "Labastide Saint Pierre", - .latitude = 43.8983333333333, - .longitude = 1.36444444444444, - .elevation = 330, - }, - { - .code = "LF8259", - .name = "Fabas", - .latitude = 43.8538888888889, - .longitude = 1.35888888888889, - .elevation = 486, - }, - { - .code = "LF8261", - .name = "Nadesse", - .latitude = 43.8541666666667, - .longitude = 1.18694444444444, - .elevation = 390, - }, - { - .code = "LF8262", - .name = "Boissay Ludovic", - .latitude = 44.1083333333333, - .longitude = 0.987777777777778, - .elevation = 312, - }, - { - .code = "LF8324", - .name = "La Roquebrussanne", - .latitude = 43.3291666666667, - .longitude = 5.99694444444444, - .elevation = 1115, - }, - { - .code = "LF8325", - .name = "Club Ulm de Themes", - .latitude = 43.3113888888889, - .longitude = 6.12694444444444, - .elevation = 1489, - }, - { - .code = "LF8329", - .name = "Brue Auriac", - .latitude = 43.5055555555556, - .longitude = 5.91861111111111, - .elevation = 900, - }, - { - .code = "LF8352", - .name = "Frejus", - .latitude = 43.4230555555555, - .longitude = 6.69777777777778, - .elevation = 15, - }, - { - .code = "LF8353", - .name = "Cogolin Grimaud", - .latitude = 43.2577777777778, - .longitude = 6.54361111111111, - .elevation = 20, - }, - { - .code = "LF8355", - .name = "Pourrieres", - .latitude = 43.48, - .longitude = 5.71027777777778, - .elevation = 787, - }, - { - .code = "LF8356", - .name = "Basse Maure", - .latitude = 43.53, - .longitude = 6.31527777777778, - .elevation = 1100, - }, - { - .code = "LF8357", - .name = "Pampelonne", - .latitude = 43.6841666666667, - .longitude = 6.13638888888889, - .elevation = 1900, - }, - { - .code = "LF8358", - .name = "Les Ailes du Soleil", - .latitude = 43.4144444444444, - .longitude = 6.72388888888889, - .elevation = 19, - }, - { - .code = "LF8359", - .name = "Golfe de Frejus", - .latitude = 43.3344444444444, - .longitude = 6.69861111111111, - .elevation = 0, - }, - { - .code = "LF8360", - .name = "les Queyrons", - .latitude = 43.3463888888889, - .longitude = 6.31111111111111, - .elevation = 430, - }, - { - .code = "LF8361", - .name = "Golfe de Saint Tropez", - .latitude = 43.2727777777778, - .longitude = 6.60888888888889, - .elevation = 0, - }, - { - .code = "LF8362", - .name = "Liberty Duck", - .latitude = 43.4675, - .longitude = 6.74027777777778, - .elevation = 66, - }, - { - .code = "LF8363", - .name = "La LIMATE", - .latitude = 43.2588888888889, - .longitude = 5.88277777777778, - .elevation = 2250, - }, - { - .code = "LF8364", - .name = "Flayosc", - .latitude = 43.5372222222222, - .longitude = 6.31888888888889, - .elevation = 1200, - }, - { - .code = "LF8421", - .name = "Saint Martin de Castillon", - .latitude = 43.8530555555556, - .longitude = 5.55027777777778, - .elevation = 1082, - }, - { - .code = "LF8424", - .name = "Coustellet", - .latitude = 43.8691666666667, - .longitude = 5.15805555555556, - .elevation = 361, - }, - { - .code = "LF8425", - .name = "Puget sur Durance", - .latitude = 43.7475, - .longitude = 5.27527777777778, - .elevation = 436, - }, - { - .code = "LF8451", - .name = "Orange Plan de Dieu", - .latitude = 44.1816666666667, - .longitude = 4.92472222222222, - .elevation = 312, - }, - { - .code = "LF8521", - .name = "Talmont Vendee Air Park", - .latitude = 46.4936111111111, - .longitude = -1.57638888888889, - .elevation = 150, - }, - { - .code = "LF8522", - .name = "La Tranche sur Mer", - .latitude = 46.3636111111111, - .longitude = -1.42722222222222, - .elevation = 16, - }, - { - .code = "LF8523", - .name = "Atlantic Air Park", - .latitude = 46.4619444444444, - .longitude = -1.24027777777778, - .elevation = 20, - }, - { - .code = "LF8524", - .name = "Le Girouard", - .latitude = 46.5783333333333, - .longitude = -1.60666666666667, - .elevation = 150, - }, - { - .code = "LF8528", - .name = "Lucon", - .latitude = 46.4247222222222, - .longitude = -1.19333333333333, - .elevation = 11, - }, - { - .code = "LF8529", - .name = "Saint Laurent sur Sevre", - .latitude = 46.9380555555556, - .longitude = -0.915555555555556, - .elevation = 643, - }, - { - .code = "LF8551", - .name = "Breuil Barret", - .latitude = 46.6605555555556, - .longitude = -0.663611111111111, - .elevation = 680, - }, - { - .code = "LF8562", - .name = "St Philbert de Bouaine", - .latitude = 47.0211111111111, - .longitude = -1.49222222222222, - .elevation = 82, - }, - { - .code = "LF8563", - .name = "Coex La Boissiere", - .latitude = 46.7236111111111, - .longitude = -1.75777777777778, - .elevation = 115, - }, - { - .code = "LF8566", - .name = "Mouchamps", - .latitude = 46.8086111111111, - .longitude = -1.03055555555556, - .elevation = 330, - }, - { - .code = "LF8567", - .name = "la brossette ", - .latitude = 46.8283333333333, - .longitude = -1.30555555555556, - .elevation = 250, - }, - { - .code = "LF8568", - .name = "Les Fontenelles", - .latitude = 46.4452777777778, - .longitude = -1.44083333333333, - .elevation = 62, - }, - { - .code = "LF8569", - .name = "Les Guifettes", - .latitude = 46.425, - .longitude = -1.18833333333333, - .elevation = 0, - }, - { - .code = "LF8570", - .name = "Les Ailes de la Moriere", - .latitude = 46.6266666666667, - .longitude = -1.74388888888889, - .elevation = 164, - }, - { - .code = "LF8571", - .name = "Saint Aubin la Plaine", - .latitude = 46.5186111111111, - .longitude = -1.05472222222222, - .elevation = 154, - }, - { - .code = "LF8572", - .name = "Saint Martin des Fontaines", - .latitude = 46.5536111111111, - .longitude = -0.900555555555556, - .elevation = 200, - }, - { - .code = "LF8573", - .name = "Coutigny- Serigne 85", - .latitude = 46.4894444444444, - .longitude = -0.870833333333333, - .elevation = 30, - }, - { - .code = "LF8621", - .name = "Le Fort d'Aslonnes", - .latitude = 46.4377777777778, - .longitude = 0.341666666666667, - .elevation = 430, - }, - { - .code = "LF8622", - .name = "Buxeuil Saint Remy sur Creuse", - .latitude = 46.95, - .longitude = 0.668611111111111, - .elevation = 370, - }, - { - .code = "LF8623", - .name = "Genouille", - .latitude = 46.108056, - .longitude = 0.358056, - .elevation = 0, - }, - { - .code = "LF8626", - .name = "St Secondin", - .latitude = 46.3466666666667, - .longitude = 0.518055555555556, - .elevation = 443, - }, - { - .code = "LF8627", - .name = "Archigny Chenevelles", - .latitude = 46.6955555555556, - .longitude = 0.655555555555556, - .elevation = 446, - }, - { - .code = "LF8651", - .name = "Montmorillon", - .latitude = 46.3908333333333, - .longitude = 0.948333333333333, - .elevation = 540, - }, - { - .code = "LF8652", - .name = "Pouancay", - .latitude = 47.0961111111111, - .longitude = -0.0725, - .elevation = 133, - }, - { - .code = "LF8653", - .name = "Availles Limouzine", - .latitude = 46.1286111111111, - .longitude = 0.695277777777778, - .elevation = 712, - }, - { - .code = "LF8654", - .name = "Brigueil le Chantre", - .latitude = 46.3669444444444, - .longitude = 1.08083333333333, - .elevation = 623, - }, - { - .code = "LF8655", - .name = "Poue", - .latitude = 46.7830555555556, - .longitude = 0.115277777777778, - .elevation = 361, - }, - { - .code = "LF8723", - .name = "Les Salles", - .latitude = 45.7419444444444, - .longitude = 0.669722222222222, - .elevation = 900, - }, - { - .code = "LF8726", - .name = "Bellac", - .latitude = 46.1302777777778, - .longitude = 1.07805555555556, - .elevation = 820, - }, - { - .code = "LF8752", - .name = "Libarderie Blond", - .latitude = 46.0597222222222, - .longitude = 0.985833333333333, - .elevation = 918, - }, - { - .code = "LF8753", - .name = "Gajoubert", - .latitude = 46.1222222222222, - .longitude = 0.858055555555556, - .elevation = 777, - }, - { - .code = "LF8754", - .name = "La Geneytouse", - .latitude = 45.7838888888889, - .longitude = 1.46138888888889, - .elevation = 1350, - }, - { - .code = "LF8755", - .name = "Azat le Ris", - .latitude = 46.3319444444444, - .longitude = 1.03444444444444, - .elevation = 657, - }, - { - .code = "LF8756", - .name = "L'Age", - .latitude = 45.6027777777778, - .longitude = 1.51527777777778, - .elevation = 1411, - }, - { - .code = "LF8757", - .name = "Bataillou", - .latitude = 45.7688888888889, - .longitude = 0.781111111111111, - .elevation = 961, - }, - { - .code = "LF8758", - .name = "Berneuil", - .latitude = 46.0516666666667, - .longitude = 1.10166666666667, - .elevation = 975, - }, - { - .code = "LF8759", - .name = "Saint Hilaire", - .latitude = 46.2547222222222, - .longitude = 1.3425, - .elevation = 919, - }, - { - .code = "LF8821", - .name = "La Tete des Champs", - .latitude = 47.9166666666667, - .longitude = 6.83055555555556, - .elevation = 3182, - }, - { - .code = "LF8851", - .name = "Ramonchamp", - .latitude = 47.8955555555556, - .longitude = 6.75472222222222, - .elevation = 1893, - }, - { - .code = "LF8852", - .name = "Dropt", - .latitude = 47.9591666666667, - .longitude = 6.54222222222222, - .elevation = 2040, - }, - { - .code = "LF8854", - .name = "Chateau d'eau", - .latitude = 48.1077777777778, - .longitude = 5.83416666666667, - .elevation = 1312, - }, - { - .code = "LF8922", - .name = "Courgenay", - .latitude = 48.3147222222222, - .longitude = 3.55972222222222, - .elevation = 581, - }, - { - .code = "LF8928", - .name = "Perreux", - .latitude = 47.875, - .longitude = 3.13555555555556, - .elevation = 610, - }, - { - .code = "LF8929", - .name = "Treigny", - .latitude = 47.5508333333333, - .longitude = 3.19694444444444, - .elevation = 918, - }, - { - .code = "LF8951", - .name = "Cravant Vincelles", - .latitude = 47.6905555555556, - .longitude = 3.66333333333333, - .elevation = 360, - }, - { - .code = "LF8952", - .name = "Vaufoin", - .latitude = 48.1063888888889, - .longitude = 3.35666666666667, - .elevation = 590, - }, - { - .code = "LF8953", - .name = "Egriselles-le-Bocage", - .latitude = 48.1169444444444, - .longitude = 3.16861111111111, - .elevation = 643, - }, - { - .code = "LF8954", - .name = "Voisines", - .latitude = 48.2883333333333, - .longitude = 3.41305555555556, - .elevation = 660, - }, - { - .code = "LF8955", - .name = "Saint Fargeau", - .latitude = 47.6219444444444, - .longitude = 3.10638888888889, - .elevation = 665, - }, - { - .code = "LF8957", - .name = "Saint Martin des Champs", - .latitude = 47.6652777777778, - .longitude = 3.04416666666667, - .elevation = 665, - }, - { - .code = "LF8959", - .name = "L'Aubepine", - .latitude = 47.6938888888889, - .longitude = 3.94444444444444, - .elevation = 850, - }, - { - .code = "LF9151", - .name = "Genevrelle a Maisse", - .latitude = 48.3883333333333, - .longitude = 2.34916666666667, - .elevation = 420, - }, - { - .code = "LF9152", - .name = "Boigny Mereville", - .latitude = 48.3294444444444, - .longitude = 2.08861111111111, - .elevation = 436, - }, - { - .code = "LF9154", - .name = "le fond du lary blanc", - .latitude = 48.3522222222222, - .longitude = 2.35, - .elevation = 367, - }, - { - .code = "LF9551", - .name = "Avernes", - .latitude = 49.1058333333333, - .longitude = 1.87888888888889, - .elevation = 456, - }, - { - .code = "LFA010", - .name = "Clamensane", - .latitude = 44.3138888888889, - .longitude = 6.07444444444444, - .elevation = 2933, - }, - { - .code = "LFA011", - .name = "Claveisolles", - .latitude = 46.0780555555556, - .longitude = 4.54722222222222, - .elevation = 2461, - }, - { - .code = "LFA019", - .name = "Col Saint Jean", - .latitude = 44.4138888888889, - .longitude = 6.37305555555556, - .elevation = 6201, - }, - { - .code = "LFA035", - .name = "Glacier Du Tour", - .latitude = 45.9833333333333, - .longitude = 7.0, - .elevation = 10170, - }, - { - .code = "LFA037", - .name = "Hautacam", - .latitude = 42.9938888888889, - .longitude = -0.0291666666666667, - .elevation = 5512, - }, - { - .code = "LFA042", - .name = "L'escoulin", - .latitude = 44.825, - .longitude = 5.23333333333333, - .elevation = 2165, - }, - { - .code = "LFA049", - .name = "La Taillade", - .latitude = 44.8916666666667, - .longitude = 2.95694444444444, - .elevation = 2913, - }, - { - .code = "LFA077", - .name = "Serre Mottaire", - .latitude = 44.7122222222222, - .longitude = 5.69166666666667, - .elevation = 5000, - }, - { - .code = "LFA078", - .name = "Mont Gerbier De Jonc", - .latitude = 44.8419444444444, - .longitude = 4.195, - .elevation = 4460, - }, - { - .code = "LFA082", - .name = "Tignes Le Palet", - .latitude = 45.4541666666667, - .longitude = 6.84861111111111, - .elevation = 8000, - }, - { - .code = "LFAB", - .name = "Dieppe Saint Aubin", - .latitude = 49.8826333333333, - .longitude = 1.08533055555556, - .elevation = 344, - }, - { - .code = "LFAC", - .name = "Calais Dunkerque", - .latitude = 50.9609333333333, - .longitude = 1.95143333333333, - .elevation = 12, - }, - { - .code = "LFAD", - .name = "Compiegne Margny", - .latitude = 49.4336111111111, - .longitude = 2.80472222222222, - .elevation = 316, - }, - { - .code = "LFAE", - .name = "Eu Mers Le Treport", - .latitude = 50.0691666666667, - .longitude = 1.42666666666667, - .elevation = 328, - }, - { - .code = "LFAF", - .name = "Laon Chambry", - .latitude = 49.5947222222222, - .longitude = 3.63027777777778, - .elevation = 258, - }, - { - .code = "LFAG", - .name = "Peronne Saint Quentin", - .latitude = 49.8688611111111, - .longitude = 3.0296, - .elevation = 295, - }, - { - .code = "LFAI", - .name = "Nangis Les Loges", - .latitude = 48.5969444444444, - .longitude = 3.00805555555556, - .elevation = 428, - }, - { - .code = "LFAJ", - .name = "Argentan", - .latitude = 48.7094444444445, - .longitude = 0.00277777777777778, - .elevation = 581, - }, - { - .code = "LFAK", - .name = "Dunkerque Les Moeres", - .latitude = 51.0405555555556, - .longitude = 2.55027777777778, - .elevation = -3, - }, - { - .code = "LFAL", - .name = "La Fleche Thoree Les Pins", - .latitude = 47.6927777777778, - .longitude = -0.00194444444444444, - .elevation = 120, - }, - { - .code = "LFAM", - .name = "Berck Sur Mer", - .latitude = 50.4230555555555, - .longitude = 1.59194444444444, - .elevation = 32, - }, - { - .code = "LFAO", - .name = "Bagnoles De L'orne Couterne", - .latitude = 48.5447222222222, - .longitude = -0.385, - .elevation = 714, - }, - { - .code = "LFAP", - .name = "Rethel Perthes", - .latitude = 49.4811111111111, - .longitude = 4.36333333333333, - .elevation = 416, - }, - { - .code = "LFAQ", - .name = "Albert Bray", - .latitude = 49.9700611111111, - .longitude = 2.69261666666667, - .elevation = 363, - }, - { - .code = "LFAR", - .name = "Montdidier", - .latitude = 49.6730555555555, - .longitude = 2.56916666666667, - .elevation = 358, - }, - { - .code = "LFAS", - .name = "Falaise Monts D'eraines", - .latitude = 48.9269444444444, - .longitude = -0.144722222222222, - .elevation = 513, - }, - { - .code = "LFAT", - .name = "Le Touquet Cote D'opale", - .latitude = 50.5148472222222, - .longitude = 1.62757777777778, - .elevation = 21, - }, - { - .code = "LFAU", - .name = "Vauville", - .latitude = 49.6227777777778, - .longitude = -1.83, - .elevation = 458, - }, - { - .code = "LFAV", - .name = "Valenciennes Denain", - .latitude = 50.3247916666667, - .longitude = 3.46544444444444, - .elevation = 165, - }, - { - .code = "LFAW", - .name = "Villerupt", - .latitude = 49.4105555555556, - .longitude = 5.88916666666667, - .elevation = 1303, - }, - { - .code = "LFAX", - .name = "Mortagne Au Perche", - .latitude = 48.5397222222222, - .longitude = 0.534166666666667, - .elevation = 886, - }, - { - .code = "LFAY", - .name = "Amiens-Glisy", - .latitude = 49.8731027777778, - .longitude = 2.38698611111111, - .elevation = 208, - }, - { - .code = "LFBA", - .name = "Agen La Garenne", - .latitude = 44.1747138888889, - .longitude = 0.590619444444444, - .elevation = 204, - }, - { - .code = "LFBC", - .name = "Cazaux", - .latitude = 44.5348861111111, - .longitude = -1.13145277777778, - .elevation = 85, - }, - { - .code = "LFBD", - .name = "Bordeaux Merignac", - .latitude = 44.8286527777778, - .longitude = -0.715344444444444, - .elevation = 166, - }, - { - .code = "LFBE", - .name = "Bergerac Dordogne Perigord", - .latitude = 44.8244305555556, - .longitude = 0.520525, - .elevation = 172, - }, - { - .code = "LFBF", - .name = "Toulouse Francazal", - .latitude = 43.5490611111111, - .longitude = 1.35726111111111, - .elevation = 535, - }, - { - .code = "LFBG", - .name = "Cognac Chateaubernard", - .latitude = 45.6582305555556, - .longitude = -0.317566666666667, - .elevation = 103, - }, - { - .code = "LFBH", - .name = "La Rochelle Ile De Re", - .latitude = 46.1792111111111, - .longitude = -1.19523611111111, - .elevation = 74, - }, - { - .code = "LFBI", - .name = "Poitiers Biard", - .latitude = 46.5873972222222, - .longitude = 0.306786111111111, - .elevation = 423, - }, - { - .code = "LFBJ", - .name = "Saint Junien", - .latitude = 45.9025, - .longitude = 0.918888888888889, - .elevation = 903, - }, - { - .code = "LFBK", - .name = "Montlucon Gueret", - .latitude = 46.2260944444444, - .longitude = 2.36281666666667, - .elevation = 1367, - }, - { - .code = "LFBL", - .name = "Limoges Bellegarde", - .latitude = 45.8607638888889, - .longitude = 1.18030555555556, - .elevation = 1300, - }, - { - .code = "LFBM", - .name = "Mont De Marsan", - .latitude = 43.9113888888889, - .longitude = -0.509444444444444, - .elevation = 203, - }, - { - .code = "LFBN", - .name = "Niort Marais Poitevin", - .latitude = 46.3134222222222, - .longitude = -0.394433333333333, - .elevation = 201, - }, - { - .code = "LFBO", - .name = "Toulouse Blagnac", - .latitude = 43.6351277777778, - .longitude = 1.36785555555556, - .elevation = 499, - }, - { - .code = "LFBP", - .name = "Pau Pyrenees", - .latitude = 43.3799, - .longitude = -0.418511111111111, - .elevation = 616, - }, - { - .code = "LFBR", - .name = "Muret Lherm", - .latitude = 43.4491555555555, - .longitude = 1.26369444444444, - .elevation = 623, - }, - { - .code = "LFBS", - .name = "Biscarrosse Parentis", - .latitude = 44.3680555555556, - .longitude = -1.13222222222222, - .elevation = 100, - }, - { - .code = "LFBT", - .name = "Tarbes Lourdes Pyrenees", - .latitude = 43.18545, - .longitude = -0.00289444444444444, - .elevation = 1260, - }, - { - .code = "LFBU", - .name = "Angouleme Brie Champniers", - .latitude = 45.729475, - .longitude = 0.219152777777778, - .elevation = 436, - }, - { - .code = "LFBX", - .name = "Perigueux Bassillac", - .latitude = 45.1974888888889, - .longitude = 0.815216666666667, - .elevation = 328, - }, - { - .code = "LFBY", - .name = "Dax Seyresse", - .latitude = 43.6891666666667, - .longitude = -1.06888888888889, - .elevation = 108, - }, - { - .code = "LFBZ", - .name = "Biarritz Pays Basque", - .latitude = 43.4683083333333, - .longitude = -1.53116111111111, - .elevation = 245, - }, - { - .code = "LFCA", - .name = "Chatellerault Targe", - .latitude = 46.7802777777778, - .longitude = 0.550555555555556, - .elevation = 210, - }, - { - .code = "LFCB", - .name = "Bagneres De Luchon", - .latitude = 42.8005555555556, - .longitude = 0.601111111111111, - .elevation = 2028, - }, - { - .code = "LFCC", - .name = "Cahors Lalbenque", - .latitude = 44.3505416666667, - .longitude = 1.47858611111111, - .elevation = 912, - }, - { - .code = "LFCD", - .name = "Andernos Les Bains", - .latitude = 44.755, - .longitude = -1.065, - .elevation = 64, - }, - { - .code = "LFCE", - .name = "Gueret Saint Laurent", - .latitude = 46.1755555555556, - .longitude = 1.95305555555556, - .elevation = 1208, - }, - { - .code = "LFCF", - .name = "Figeac Livernon", - .latitude = 44.6725, - .longitude = 1.78805555555556, - .elevation = 1085, - }, - { - .code = "LFCG", - .name = "Saint Girons Antichan", - .latitude = 43.0077777777778, - .longitude = 1.10305555555556, - .elevation = 1376, - }, - { - .code = "LFCH", - .name = "Arcachon La Teste De Buch", - .latitude = 44.5969444444444, - .longitude = -1.11388888888889, - .elevation = 52, - }, - { - .code = "LFCI", - .name = "Albi Le Sequestre", - .latitude = 43.9132777777778, - .longitude = 2.11675, - .elevation = 565, - }, - { - .code = "LFCJ", - .name = "Jonzac Neulles", - .latitude = 45.4830555555556, - .longitude = -0.423055555555556, - .elevation = 130, - }, - { - .code = "LFCK", - .name = "Castres Mazamet", - .latitude = 43.5549611111111, - .longitude = 2.29059166666667, - .elevation = 785, - }, - { - .code = "LFCL", - .name = "Toulouse Lasbordes", - .latitude = 43.5877777777778, - .longitude = 1.49861111111111, - .elevation = 460, - }, - { - .code = "LFCM", - .name = "Millau Larzac", - .latitude = 43.9890583333333, - .longitude = 3.18330277777778, - .elevation = 2606, - }, - { - .code = "LFCN", - .name = "Nogaro", - .latitude = 43.7688888888889, - .longitude = -0.0347222222222222, - .elevation = 304, - }, - { - .code = "LFCO", - .name = "Oloron Herrere", - .latitude = 43.1647222222222, - .longitude = -0.560277777777778, - .elevation = 984, - }, - { - .code = "LFCP", - .name = "Pons Avy", - .latitude = 45.5658333333333, - .longitude = -0.513611111111111, - .elevation = 117, - }, - { - .code = "LFCQ", - .name = "Graulhet Montdragon", - .latitude = 43.7686111111111, - .longitude = 2.00777777777778, - .elevation = 583, - }, - { - .code = "LFCR", - .name = "Rodez Aveyron", - .latitude = 44.4074888888889, - .longitude = 2.48331388888889, - .elevation = 1909, - }, - { - .code = "LFCS", - .name = "Bordeaux Leognan Saucats", - .latitude = 44.6991666666667, - .longitude = -0.597222222222222, - .elevation = 192, - }, - { - .code = "LFCT", - .name = "Thouars", - .latitude = 46.9619444444444, - .longitude = -0.152777777777778, - .elevation = 341, - }, - { - .code = "LFCU", - .name = "Ussel Thalamy", - .latitude = 45.5358333333333, - .longitude = 2.42472222222222, - .elevation = 2427, - }, - { - .code = "LFCV", - .name = "Villefranche De Rouergue", - .latitude = 44.3688888888889, - .longitude = 2.02694444444444, - .elevation = 1104, - }, - { - .code = "LFCW", - .name = "Villeneuve Sur Lot", - .latitude = 44.3991777777778, - .longitude = 0.759533333333333, - .elevation = 193, - }, - { - .code = "LFCX", - .name = "Castelsarrasin Moissac", - .latitude = 44.0858333333333, - .longitude = 1.12694444444444, - .elevation = 243, - }, - { - .code = "LFCY", - .name = "Royan Medis", - .latitude = 45.6311611111111, - .longitude = -0.975488888888889, - .elevation = 72, - }, - { - .code = "LFCZ", - .name = "Mimizan", - .latitude = 44.1458861111111, - .longitude = -1.16480277777778, - .elevation = 165, - }, - { - .code = "LFDA", - .name = "Aire Sur L'adour", - .latitude = 43.7086111111111, - .longitude = -0.247222222222222, - .elevation = 266, - }, - { - .code = "LFDB", - .name = "Montauban", - .latitude = 44.0266666666667, - .longitude = 1.37694444444444, - .elevation = 353, - }, - { - .code = "LFDC", - .name = "Montendre Marcillac", - .latitude = 45.2736111111111, - .longitude = -0.453333333333333, - .elevation = 145, - }, - { - .code = "LFDE", - .name = "Egletons", - .latitude = 45.4205555555556, - .longitude = 2.06777777777778, - .elevation = 1859, - }, - { - .code = "LFDF", - .name = "Sainte Foy La Grande", - .latitude = 44.8525, - .longitude = 0.175555555555556, - .elevation = 282, - }, - { - .code = "LFDG", - .name = "Gaillac Lisle Sur Tarn", - .latitude = 43.8830555555556, - .longitude = 1.87416666666667, - .elevation = 441, - }, - { - .code = "LFDH", - .name = "Auch Gers", - .latitude = 43.6868388888889, - .longitude = 0.600047222222222, - .elevation = 411, - }, - { - .code = "LFDI", - .name = "Libourne Artigues De Lussac", - .latitude = 44.985, - .longitude = -0.136111111111111, - .elevation = 157, - }, - { - .code = "LFDJ", - .name = "Pamiers Les Pujols", - .latitude = 43.0906833333333, - .longitude = 1.69585277777778, - .elevation = 1114, - }, - { - .code = "LFDK", - .name = "Soulac Sur Mer", - .latitude = 45.4938888888889, - .longitude = -1.08388888888889, - .elevation = 11, - }, - { - .code = "LFDL", - .name = "Loudun", - .latitude = 47.0361111111111, - .longitude = 0.100833333333333, - .elevation = 313, - }, - { - .code = "LFDM", - .name = "Marmande Virazeil", - .latitude = 44.4991666666667, - .longitude = 0.200277777777778, - .elevation = 110, - }, - { - .code = "LFDN", - .name = "Rochefort Charente Maritime", - .latitude = 45.8895083333333, - .longitude = -0.982347222222222, - .elevation = 60, - }, - { - .code = "LFDP", - .name = "Saint Pierre D'oleron", - .latitude = 45.9577777777778, - .longitude = -1.31138888888889, - .elevation = 22, - }, - { - .code = "LFDQ", - .name = "Castelnau Magnoac", - .latitude = 43.2775, - .longitude = 0.519444444444444, - .elevation = 992, - }, - { - .code = "LFDR", - .name = "La Reole Floudes", - .latitude = 44.5669472222222, - .longitude = -0.05725, - .elevation = 44, - }, - { - .code = "LFDS", - .name = "Sarlat Domme", - .latitude = 44.7922222222222, - .longitude = 1.24361111111111, - .elevation = 979, - }, - { - .code = "LFDT", - .name = "Tarbes Laloubere", - .latitude = 43.215, - .longitude = 0.0775, - .elevation = 1075, - }, - { - .code = "LFDU", - .name = "Lesparre Saint Laurent Medoc", - .latitude = 45.1977777777778, - .longitude = -0.882222222222222, - .elevation = 105, - }, - { - .code = "LFDV", - .name = "Couhe Verac", - .latitude = 46.2705555555556, - .longitude = 0.188333333333333, - .elevation = 500, - }, - { - .code = "LFDW", - .name = "Chauvigny", - .latitude = 46.5833333333333, - .longitude = 0.642222222222222, - .elevation = 442, - }, - { - .code = "LFDX", - .name = "Fumel Montayral", - .latitude = 44.4591666666667, - .longitude = 1.00722222222222, - .elevation = 692, - }, - { - .code = "LFDY", - .name = "Bordeaux Yvrac", - .latitude = 44.8772222222222, - .longitude = -0.479166666666667, - .elevation = 240, - }, - { - .code = "LFEA", - .name = "Belle Ile", - .latitude = 47.3261111111111, - .longitude = -3.19888888888889, - .elevation = 177, - }, - { - .code = "LFEB", - .name = "Dinan Trelivan", - .latitude = 48.4433333333333, - .longitude = -2.10333333333333, - .elevation = 393, - }, - { - .code = "LFEC", - .name = "Ouessant", - .latitude = 48.4632138888889, - .longitude = -5.06358333333333, - .elevation = 142, - }, - { - .code = "LFED", - .name = "Pontivy", - .latitude = 48.0569444444444, - .longitude = -2.92333333333333, - .elevation = 406, - }, - { - .code = "LFEF", - .name = "Amboise Dierre", - .latitude = 47.3405555555556, - .longitude = 0.941111111111111, - .elevation = 177, - }, - { - .code = "LFEG", - .name = "Argenton Sur Creuse", - .latitude = 46.5958333333333, - .longitude = 1.60111111111111, - .elevation = 666, - }, - { - .code = "LFEH", - .name = "Aubigny Sur Nere", - .latitude = 47.4805555555556, - .longitude = 2.39416666666667, - .elevation = 630, - }, - { - .code = "LFEI", - .name = "Briare Chatillon", - .latitude = 47.6145805555556, - .longitude = 2.78185, - .elevation = 539, - }, - { - .code = "LFEJ", - .name = "Chateauroux Villers", - .latitude = 46.8408333333333, - .longitude = 1.62, - .elevation = 542, - }, - { - .code = "LFEK", - .name = "Issoudun Le Fay", - .latitude = 46.8886111111111, - .longitude = 2.04138888888889, - .elevation = 531, - }, - { - .code = "LFEL", - .name = "Le Blanc", - .latitude = 46.62, - .longitude = 1.08583333333333, - .elevation = 382, - }, - { - .code = "LFEM", - .name = "Montargis Vimory", - .latitude = 47.9605555555556, - .longitude = 2.68583333333333, - .elevation = 308, - }, - { - .code = "LFEN", - .name = "Tours Sorigny", - .latitude = 47.2666666666667, - .longitude = 0.699444444444444, - .elevation = 299, - }, - { - .code = "LFEP", - .name = "Pouilly Maconge", - .latitude = 47.2205555555556, - .longitude = 4.56027777777778, - .elevation = 1413, - }, - { - .code = "LFEQ", - .name = "Quiberon", - .latitude = 47.4813888888889, - .longitude = -3.10166666666667, - .elevation = 38, - }, - { - .code = "LFER", - .name = "Redon Bains Sur Oust", - .latitude = 47.6986111111111, - .longitude = -2.03805555555556, - .elevation = 225, - }, - { - .code = "LFES", - .name = "Guiscriff Scaer", - .latitude = 48.0537361111111, - .longitude = -3.66403611111111, - .elevation = 574, - }, - { - .code = "LFET", - .name = "Til Chatel", - .latitude = 47.5463888888889, - .longitude = 5.21083333333333, - .elevation = 939, - }, - { - .code = "LFEU", - .name = "Bar Le Duc Les Hauts De Chee", - .latitude = 48.8677777777778, - .longitude = 5.18416666666667, - .elevation = 899, - }, - { - .code = "LFEV", - .name = "Gray Saint Adrien", - .latitude = 47.4322222222222, - .longitude = 5.62138888888889, - .elevation = 678, - }, - { - .code = "LFEW", - .name = "Saulieu Liernais", - .latitude = 47.2386111111111, - .longitude = 4.26444444444444, - .elevation = 1713, - }, - { - .code = "LFEX", - .name = "Nancy Azelot", - .latitude = 48.5919444444444, - .longitude = 6.23972222222222, - .elevation = 958, - }, - { - .code = "LFEY", - .name = "Ile D'yeu", - .latitude = 46.7175, - .longitude = -2.3925, - .elevation = 79, - }, - { - .code = "LFEZ", - .name = "Nancy Malzeville", - .latitude = 48.7236111111111, - .longitude = 6.20638888888889, - .elevation = 1247, - }, - { - .code = "LFFB", - .name = "Buno Bonnevaux", - .latitude = 48.3502777777778, - .longitude = 2.42444444444444, - .elevation = 419, - }, - { - .code = "LFFC", - .name = "Mantes Cherence", - .latitude = 49.0788888888889, - .longitude = 1.68972222222222, - .elevation = 512, - }, - { - .code = "LFFD", - .name = "Saint Andre De L'eure", - .latitude = 48.8975, - .longitude = 1.25083333333333, - .elevation = 491, - }, - { - .code = "LFFE", - .name = "Enghien Moisselles", - .latitude = 49.0455555555556, - .longitude = 2.35194444444444, - .elevation = 337, - }, - { - .code = "LFFG", - .name = "La Ferte Gaucher", - .latitude = 48.7575, - .longitude = 3.27888888888889, - .elevation = 536, - }, - { - .code = "LFFH", - .name = "Chateau Thierry Belleau", - .latitude = 49.0666666666667, - .longitude = 3.35555555555556, - .elevation = 723, - }, - { - .code = "LFFI", - .name = "Ancenis", - .latitude = 47.4072222222222, - .longitude = -1.17888888888889, - .elevation = 109, - }, - { - .code = "LFFJ", - .name = "Joinville Mussey", - .latitude = 48.3852777777778, - .longitude = 5.14333333333333, - .elevation = 1030, - }, - { - .code = "LFFK", - .name = "Fontenay Le Comte", - .latitude = 46.4408333333333, - .longitude = -0.793888888888889, - .elevation = 80, - }, - { - .code = "LFFL", - .name = "Bailleau Armenonville", - .latitude = 48.5147222222222, - .longitude = 1.63861111111111, - .elevation = 508, - }, - { - .code = "LFFN", - .name = "Brienne Le Chateau", - .latitude = 48.4297222222222, - .longitude = 4.48222222222222, - .elevation = 376, - }, - { - .code = "LFFO", - .name = "Beauvoir Fromentine", - .latitude = 46.8905555555556, - .longitude = -2.08861111111111, - .elevation = 10, - }, - { - .code = "LFFP", - .name = "Pithiviers", - .latitude = 48.1563888888889, - .longitude = 2.19111111111111, - .elevation = 391, - }, - { - .code = "LFFQ", - .name = "La Ferte Alais", - .latitude = 48.4995277777778, - .longitude = 2.32996388888889, - .elevation = 454, - }, - { - .code = "LFFR", - .name = "Bar Sur Seine", - .latitude = 48.0661111111111, - .longitude = 4.4125, - .elevation = 938, - }, - { - .code = "LFFT", - .name = "Neufchateau", - .latitude = 48.3616666666667, - .longitude = 5.72027777777778, - .elevation = 1228, - }, - { - .code = "LFFU", - .name = "Chateauneuf Sur Cher", - .latitude = 46.8711111111111, - .longitude = 2.37694444444444, - .elevation = 551, - }, - { - .code = "LFFV", - .name = "Vierzon Mereau", - .latitude = 47.1947222222222, - .longitude = 2.06666666666667, - .elevation = 430, - }, - { - .code = "LFFW", - .name = "Montaigu Saint Georges", - .latitude = 46.9322222222222, - .longitude = -1.32722222222222, - .elevation = 186, - }, - { - .code = "LFFX", - .name = "Tournus Cuisery", - .latitude = 46.5613888888889, - .longitude = 4.97527777777778, - .elevation = 689, - }, - { - .code = "LFFY", - .name = "Etrepagny", - .latitude = 49.3052777777778, - .longitude = 1.63777777777778, - .elevation = 308, - }, - { - .code = "LFFZ", - .name = "Sezanne Saint Remy", - .latitude = 48.7094444444445, - .longitude = 3.76277777777778, - .elevation = 355, - }, - { - .code = "LFGA", - .name = "Colmar Houssen", - .latitude = 48.11035, - .longitude = 7.35914722222222, - .elevation = 627, - }, - { - .code = "LFGB", - .name = "Mulhouse Habsheim", - .latitude = 47.7372222222222, - .longitude = 7.42972222222222, - .elevation = 789, - }, - { - .code = "LFGC", - .name = "Strasbourg Neuhof", - .latitude = 48.5536111111111, - .longitude = 7.7775, - .elevation = 459, - }, - { - .code = "LFGE", - .name = "Avallon", - .latitude = 47.5019444444444, - .longitude = 3.89833333333333, - .elevation = 786, - }, - { - .code = "LFGF", - .name = "Beaune Challanges", - .latitude = 47.0102777777778, - .longitude = 4.89638888888889, - .elevation = 656, - }, - { - .code = "LFGG", - .name = "Belfort Chaux", - .latitude = 47.700975, - .longitude = 6.83083333333333, - .elevation = 1367, - }, - { - .code = "LFGH", - .name = "Cosne Sur Loire", - .latitude = 47.3602777777778, - .longitude = 2.91833333333333, - .elevation = 580, - }, - { - .code = "LFGI", - .name = "Dijon Darois", - .latitude = 47.3852777777778, - .longitude = 4.94694444444445, - .elevation = 1586, - }, - { - .code = "LFGJ", - .name = "Dole Tavaux", - .latitude = 47.0426944444444, - .longitude = 5.43492777777778, - .elevation = 645, - }, - { - .code = "LFGK", - .name = "Joigny", - .latitude = 47.9944444444444, - .longitude = 3.39083333333333, - .elevation = 732, - }, - { - .code = "LFGL", - .name = "Lons Le Saunier Courlaoux", - .latitude = 46.675, - .longitude = 5.46916666666667, - .elevation = 762, - }, - { - .code = "LFGM", - .name = "Montceau Les Mines Pouilloux", - .latitude = 46.6033333333333, - .longitude = 4.33277777777778, - .elevation = 1032, - }, - { - .code = "LFGN", - .name = "Paray Le Monial", - .latitude = 46.4666666666667, - .longitude = 4.13305555555556, - .elevation = 1003, - }, - { - .code = "LFGO", - .name = "Pont Sur Yonne", - .latitude = 48.2894444444444, - .longitude = 3.24888888888889, - .elevation = 232, - }, - { - .code = "LFGP", - .name = "Saint Florentin Cheu", - .latitude = 47.9813888888889, - .longitude = 3.77694444444444, - .elevation = 355, - }, - { - .code = "LFGQ", - .name = "Semur En Auxois", - .latitude = 47.4811111111111, - .longitude = 4.34305555555556, - .elevation = 1051, - }, - { - .code = "LFGR", - .name = "Doncourt Les Conflans", - .latitude = 49.1519722222222, - .longitude = 5.93127777777778, - .elevation = 809, - }, - { - .code = "LFGS", - .name = "Longuyon Villette", - .latitude = 49.4836111111111, - .longitude = 5.57194444444444, - .elevation = 1153, - }, - { - .code = "LFGT", - .name = "Sarrebourg Buhl", - .latitude = 48.7183333333333, - .longitude = 7.08, - .elevation = 873, - }, - { - .code = "LFGU", - .name = "Sarreguemines Neunkirch", - .latitude = 49.1275, - .longitude = 7.10666666666667, - .elevation = 863, - }, - { - .code = "LFGW", - .name = "Verdun Sommedieue", - .latitude = 49.1221805555556, - .longitude = 5.47085277777778, - .elevation = 1236, - }, - { - .code = "LFGX", - .name = "Champagnole Crotenay", - .latitude = 46.7633333333333, - .longitude = 5.81972222222222, - .elevation = 1745, - }, - { - .code = "LFGY", - .name = "Saint Die Remomeix", - .latitude = 48.2663888888889, - .longitude = 7.0075, - .elevation = 1187, - }, - { - .code = "LFGZ", - .name = "Nuits Saint Georges", - .latitude = 47.1422222222222, - .longitude = 4.96833333333333, - .elevation = 794, - }, - { - .code = "LFH1", - .name = "Abbeville Centre Hospitalier", - .latitude = 50.1015388888889, - .longitude = 1.83131388888889, - .elevation = 82, - }, - { - .code = "LFH10", - .name = "Angouleme Centre Hospitalier", - .latitude = 45.6341666666667, - .longitude = 0.117777777777778, - .elevation = 154, - }, - { - .code = "LFH101", - .name = "Granville Centre Hospitalier J. Monod", - .latitude = 48.8269444444445, - .longitude = -1.56944444444444, - .elevation = 161, - }, - { - .code = "LFH102", - .name = "Grenoble Hopital Nord", - .latitude = 45.2009361111111, - .longitude = 5.74527777777778, - .elevation = 716, - }, - { - .code = "LFH103", - .name = "Grimaud Sarl R.C.E.", - .latitude = 43.2678055555556, - .longitude = 6.551925, - .elevation = 21, - }, - { - .code = "LFH104", - .name = "Guyancourt Les Sangliers", - .latitude = 48.7833333333333, - .longitude = 2.07666666666667, - .elevation = 518, - }, - { - .code = "LFH108", - .name = "Ile D'yeu Port Joinville", - .latitude = 46.7333333333333, - .longitude = -2.35, - .elevation = 10, - }, - { - .code = "LFH11", - .name = "Carcassonne Montredon Centre Hospitalier", - .latitude = 43.2197222222222, - .longitude = 2.39444444444444, - .elevation = 352, - }, - { - .code = "LFH110", - .name = "Istres S.E.P.", - .latitude = 43.5438888888889, - .longitude = 4.95194444444444, - .elevation = 72, - }, - { - .code = "LFH116", - .name = "Lacanau Le Huga", - .latitude = 45.0069444444444, - .longitude = -1.16472222222222, - .elevation = 52, - }, - { - .code = "LFH117", - .name = "La Roche Sur Yon Centre Hospitalier", - .latitude = 46.6680555555556, - .longitude = -1.41222222222222, - .elevation = 343, - }, - { - .code = "LFH118", - .name = "Lannion Centre Hospitalier", - .latitude = 48.7227777777778, - .longitude = -3.46527777777778, - .elevation = 92, - }, - { - .code = "LFH119", - .name = "Laon Centre Hospitalier", - .latitude = 49.5633333333333, - .longitude = 3.61166666666667, - .elevation = 607, - }, - { - .code = "LFH12", - .name = "Annecy Centre Hospitalier", - .latitude = 45.9313888888889, - .longitude = 6.11833333333333, - .elevation = 1512, - }, - { - .code = "LFH120", - .name = "Le Creusot Centre Hospitalier Hotel Dieu", - .latitude = 46.805, - .longitude = 4.44902222222222, - .elevation = 1180, - }, - { - .code = "LFH123", - .name = "Lille Centre Hospitalier Regional", - .latitude = 50.6041666666667, - .longitude = 3.035, - .elevation = 110, - }, - { - .code = "LFH124", - .name = "Limoges Centre Hospitalier", - .latitude = 45.8138638888889, - .longitude = 1.23781111111111, - .elevation = 899, - }, - { - .code = "LFH127", - .name = "Saran Pole Sante Oreliance", - .latitude = 47.9383333333333, - .longitude = 1.87861111111111, - .elevation = 394, - }, - { - .code = "LFH128", - .name = "Lyon Hopital Edouard Herriot", - .latitude = 45.7438888888889, - .longitude = 4.88305555555556, - .elevation = 658, - }, - { - .code = "LFH129", - .name = "Lyon La Sauvegarde", - .latitude = 45.7888888888889, - .longitude = 4.78694444444444, - .elevation = 906, - }, - { - .code = "LFH13", - .name = "Annonay Centre Hospitalier", - .latitude = 45.2417083333333, - .longitude = 4.66584444444444, - .elevation = 1364, - }, - { - .code = "LFH133", - .name = "Mantes La Jolie Centre Hospitalier Francois Quesnay", - .latitude = 48.9990333333333, - .longitude = 1.67494166666667, - .elevation = 92, - }, - { - .code = "LFH135", - .name = "Margaux Relais De Margaux", - .latitude = 45.0566666666667, - .longitude = -0.6575, - .elevation = 10, - }, - { - .code = "LFH136", - .name = "Marseille Hopital Nord", - .latitude = 43.38, - .longitude = 5.36305555555556, - .elevation = 643, - }, - { - .code = "LFH137", - .name = "Marseille Hopital De La Timone", - .latitude = 43.2897222222222, - .longitude = 5.4025, - .elevation = 205, - }, - { - .code = "LFH138", - .name = "Martigues Centre De Secours", - .latitude = 43.422575, - .longitude = 5.04808888888889, - .elevation = 136, - }, - { - .code = "LFH14", - .name = "Antibes Port Vauban", - .latitude = 43.5881944444444, - .longitude = 7.13234166666667, - .elevation = 22, - }, - { - .code = "LFH143", - .name = "Mont De Lans Les Deux Alpes", - .latitude = 45.0102777777778, - .longitude = 6.14408333333333, - .elevation = 7152, - }, - { - .code = "LFH144", - .name = "Mont De Marsan Centre Hospitalier", - .latitude = 43.8933333333333, - .longitude = -0.486111111111111, - .elevation = 197, - }, - { - .code = "LFH146", - .name = "Montpellier Le Corum", - .latitude = 43.6135361111111, - .longitude = 3.88219722222222, - .elevation = 176, - }, - { - .code = "LFH148", - .name = "Moutiers Centre Hospitalier", - .latitude = 45.4836111111111, - .longitude = 6.53555555555556, - .elevation = 1621, - }, - { - .code = "LFH15", - .name = "Archamps Technopole", - .latitude = 46.1389722222222, - .longitude = 6.12533333333333, - .elevation = 1627, - }, - { - .code = "LFH153", - .name = "Nice Hopital L'archet 2", - .latitude = 43.6973972222222, - .longitude = 7.22613333333333, - .elevation = 608, - }, - { - .code = "LFH154", - .name = "Niort Centre Hospitalier", - .latitude = 46.3161111111111, - .longitude = -0.458333333333333, - .elevation = 108, - }, - { - .code = "LFH157", - .name = "Paluel Centrale Nucleaire", - .latitude = 49.8583333333333, - .longitude = 0.627777777777778, - .elevation = 305, - }, - { - .code = "LFH16", - .name = "Bourg Saint-Maurice Centre Hospitalier", - .latitude = 45.6166666666667, - .longitude = 6.765, - .elevation = 2838, - }, - { - .code = "LFH162", - .name = "Pau Centre Hospitalier", - .latitude = 43.3280555555556, - .longitude = -0.350833333333333, - .elevation = 709, - }, - { - .code = "LFH163", - .name = "Penly Centrale Nucleaire", - .latitude = 49.9722222222222, - .longitude = 1.21388888888889, - .elevation = 322, - }, - { - .code = "LFH164", - .name = "Perigueux Centre Hospitalier", - .latitude = 45.1925, - .longitude = 0.732222222222222, - .elevation = 502, - }, - { - .code = "LFH167", - .name = "Poitiers Centre Hospitalier", - .latitude = 46.5605555555556, - .longitude = 0.382777777777778, - .elevation = 400, - }, - { - .code = "LFH168", - .name = "Pontarlier Centre Hospitalier", - .latitude = 46.9006722222222, - .longitude = 6.35970277777778, - .elevation = 2779, - }, - { - .code = "LFH172", - .name = "Quimper Cornouailles", - .latitude = 47.9852777777778, - .longitude = -4.09583333333333, - .elevation = 182, - }, - { - .code = "LFH173", - .name = "Rang Du Fliers Centre Hospitalier", - .latitude = 50.4145444444444, - .longitude = 1.66300555555556, - .elevation = 152, - }, - { - .code = "LFH174", - .name = "Reims Centre Hospitalier Regional", - .latitude = 49.2257777777778, - .longitude = 4.01851111111111, - .elevation = 339, - }, - { - .code = "LFH177", - .name = "Renneville", - .latitude = 43.3738888888889, - .longitude = 1.72555555555556, - .elevation = 623, - }, - { - .code = "LFH178", - .name = "Romans Centre Hospitalier", - .latitude = 45.0420277777778, - .longitude = 5.02186388888889, - .elevation = 526, - }, - { - .code = "LFH179", - .name = "Rouen Centre Hospitalier", - .latitude = 49.4404333333333, - .longitude = 1.11119722222222, - .elevation = 144, - }, - { - .code = "LFH18", - .name = "Aubenas Centre Hospitalier", - .latitude = 44.6140583333333, - .longitude = 4.39750555555556, - .elevation = 731, - }, - { - .code = "LFH181", - .name = "Saint Avold Centre Hospitalier", - .latitude = 49.1121222222222, - .longitude = 6.72178055555556, - .elevation = 853, - }, - { - .code = "LFH182", - .name = "Saint Brieuc Centre Hospitalier", - .latitude = 48.4908333333333, - .longitude = -2.75111111111111, - .elevation = 354, - }, - { - .code = "LFH183", - .name = "Saint Chamond Centre Hospitalier", - .latitude = 45.4760611111111, - .longitude = 4.51563333333333, - .elevation = 1249, - }, - { - .code = "LFH184", - .name = "Saint Dizier Centre Hospitalier", - .latitude = 48.6549527777778, - .longitude = 4.96495, - .elevation = 528, - }, - { - .code = "LFH19", - .name = "Avignon Centre Hospitalier", - .latitude = 43.9202666666667, - .longitude = 4.79897222222222, - .elevation = 69, - }, - { - .code = "LFH190", - .name = "Saint Lo Hopital", - .latitude = 49.1052777777778, - .longitude = -1.10611111111111, - .elevation = 131, - }, - { - .code = "LFH192", - .name = "Saint Malo Centre Hospitalier", - .latitude = 48.6388888888889, - .longitude = -2.00833333333333, - .elevation = 26, - }, - { - .code = "LFH195", - .name = "Saint Nazaire Centre Hospitalier", - .latitude = 47.2672222222222, - .longitude = -2.25638888888889, - .elevation = 169, - }, - { - .code = "LFH2", - .name = "Apt Centre Hospitalier", - .latitude = 43.8758333333333, - .longitude = 5.38194444444444, - .elevation = 869, - }, - { - .code = "LFH20", - .name = "Avranches Centre Hospitalier", - .latitude = 48.6947222222222, - .longitude = -1.35111111111111, - .elevation = 26, - }, - { - .code = "LFH201", - .name = "Saintes Centre Hospitalier", - .latitude = 45.7477777777778, - .longitude = -0.655, - .elevation = 135, - }, - { - .code = "LFH202", - .name = "Sallanches Centre Hospitalier", - .latitude = 45.9355555555556, - .longitude = 6.64194444444444, - .elevation = 1812, - }, - { - .code = "LFH208", - .name = "Strasbourg Hautepierre", - .latitude = 48.5933333333333, - .longitude = 7.705, - .elevation = 487, - }, - { - .code = "LFH21", - .name = "Ayros-Arbouix", - .latitude = 43.0027777777778, - .longitude = -0.0833333333333333, - .elevation = 1312, - }, - { - .code = "LFH218", - .name = "Val D'isere La Daille", - .latitude = 45.4572277777778, - .longitude = 6.96773611111111, - .elevation = 5912, - }, - { - .code = "LFH219", - .name = "Val D'isere Tete De Solaise", - .latitude = 45.4327777777778, - .longitude = 6.99166666666667, - .elevation = 8366, - }, - { - .code = "LFH22", - .name = "Bayonne Centre Hospitalier De La Cote Basque", - .latitude = 43.4825, - .longitude = -1.47972222222222, - .elevation = 150, - }, - { - .code = "LFH221", - .name = "Valence Centre Hospitalier", - .latitude = 44.9144722222222, - .longitude = 4.9042, - .elevation = 486, - }, - { - .code = "LFH222", - .name = "Vannes - Centre Hospitalier Bretagne Atlantique.", - .latitude = 47.6638888888889, - .longitude = -2.74722222222222, - .elevation = 33, - }, - { - .code = "LFH223", - .name = "Varces Quartier Reynies", - .latitude = 45.1, - .longitude = 5.68333333333333, - .elevation = 722, - }, - { - .code = "LFH226", - .name = "Villefranche Hopital Nord Ouest", - .latitude = 46.0055361111111, - .longitude = 4.69318888888889, - .elevation = 765, - }, - { - .code = "LFH229", - .name = "Vonnas Hotel Georges Blanc", - .latitude = 46.2208333333333, - .longitude = 4.98888888888889, - .elevation = 653, - }, - { - .code = "LFH231", - .name = "Nancy Hopital Central", - .latitude = 48.6853944444444, - .longitude = 6.192475, - .elevation = 749, - }, - { - .code = "LFH233", - .name = "Amilly Centre Hospitalier", - .latitude = 47.9967194444444, - .longitude = 2.774425, - .elevation = 353, - }, - { - .code = "LFH236", - .name = "Aix En Provence Centre Hospitalier", - .latitude = 43.5347166666667, - .longitude = 5.44223611111111, - .elevation = 721, - }, - { - .code = "LFH237", - .name = "Dreux Centre Hospitalier", - .latitude = 48.727475, - .longitude = 1.38468611111111, - .elevation = 451, - }, - { - .code = "LFH238", - .name = "Chatillon Sur Seine Centre Hospitalier", - .latitude = 47.8616666666667, - .longitude = 4.55888888888889, - .elevation = 792, - }, - { - .code = "LFH24", - .name = "Berck Sur Mer Centre Hospitalier Helio-Marin", - .latitude = 50.4184611111111, - .longitude = 1.56428333333333, - .elevation = 42, - }, - { - .code = "LFH240", - .name = "Aulnay Sous Bois Centre Hospitalier", - .latitude = 48.9544444444444, - .longitude = 2.52111111111111, - .elevation = 190, - }, - { - .code = "LFH241", - .name = "Poissy Centre Hospitalier.", - .latitude = 48.9169444444444, - .longitude = 2.02333333333333, - .elevation = 233, - }, - { - .code = "LFH244", - .name = "Saumur Centre Hospitalier", - .latitude = 47.2455555555556, - .longitude = -0.0594444444444444, - .elevation = 272, - }, - { - .code = "LFH25", - .name = "Epinal Emile Durkheim Centre Hospitalier", - .latitude = 48.1811111111111, - .longitude = 6.45444444444444, - .elevation = 1295, - }, - { - .code = "LFH250", - .name = "Sandouville Usine Renault", - .latitude = 49.4767777777778, - .longitude = 0.302594444444444, - .elevation = 17, - }, - { - .code = "LFH251", - .name = "Saint Ouen L'aumone Heliport (Heli Industries)", - .latitude = 49.0577666666667, - .longitude = 2.14483611111111, - .elevation = 135, - }, - { - .code = "LFH252", - .name = "Chateauroux Centre Hospitalier", - .latitude = 46.7994444444444, - .longitude = 1.6975, - .elevation = 558, - }, - { - .code = "LFH253", - .name = "Toulouse Rangueil Pech David", - .latitude = 43.5612583333333, - .longitude = 1.44863055555556, - .elevation = 793, - }, - { - .code = "LFH255", - .name = "Angers Centre Hospitalier", - .latitude = 47.4861111111111, - .longitude = -0.554166666666667, - .elevation = 138, - }, - { - .code = "LFH257", - .name = "Boulogne Sur Mer Centre Hospitalier", - .latitude = 50.7229472222222, - .longitude = 1.62887777777778, - .elevation = 279, - }, - { - .code = "LFH258", - .name = "Chartres Centre Hospitalier", - .latitude = 48.42, - .longitude = 1.50472222222222, - .elevation = 488, - }, - { - .code = "LFH26", - .name = "Douai Centre Hospitalier", - .latitude = 50.3372777777778, - .longitude = 3.10125, - .elevation = 144, - }, - { - .code = "LFH263", - .name = "Saint Denis Chd", - .latitude = -20.8910305555556, - .longitude = 55.444075, - .elevation = 390, - }, - { - .code = "LFH264", - .name = "Saint Pierre Chu Sud", - .latitude = -21.3457111111111, - .longitude = 55.4933888888889, - .elevation = 269, - }, - { - .code = "LFH266", - .name = "Challans", - .latitude = 46.8541666666667, - .longitude = -1.83055555555556, - .elevation = 130, - }, - { - .code = "LFH267", - .name = "Fecamp Centre Hospitalier", - .latitude = 49.7430555555556, - .longitude = 0.385555555555556, - .elevation = 318, - }, - { - .code = "LFH268", - .name = "Romorantin Centre Hospitalier", - .latitude = 47.3605555555556, - .longitude = 1.73194444444444, - .elevation = 293, - }, - { - .code = "LFH27", - .name = "Beziers Hopital Montimaran", - .latitude = 43.3414277777778, - .longitude = 3.25497222222222, - .elevation = 176, - }, - { - .code = "LFH270", - .name = "Saint Paul L'eperon", - .latitude = -21.0349083333333, - .longitude = 55.2602833333333, - .elevation = 834, - }, - { - .code = "LFH271", - .name = "Bourges Centre Hospitalier", - .latitude = 47.0841666666667, - .longitude = 2.43527777777778, - .elevation = 445, - }, - { - .code = "LFH272", - .name = "Saint Omer Centre Hospitalier", - .latitude = 50.7035833333333, - .longitude = 2.25480555555556, - .elevation = 276, - }, - { - .code = "LFH273", - .name = "Grasse Hopital Clavary", - .latitude = 43.6196111111111, - .longitude = 6.92890277777778, - .elevation = 552, - }, - { - .code = "LFH274", - .name = "Nice Hopital Lenval", - .latitude = 43.6893333333333, - .longitude = 7.24163333333333, - .elevation = 115, - }, - { - .code = "LFH275", - .name = "Brignoles Hopital Jean Marcel", - .latitude = 43.4030527777778, - .longitude = 6.06630833333333, - .elevation = 753, - }, - { - .code = "LFH276", - .name = "Frejus Hopital Bonnet", - .latitude = 43.4397416666667, - .longitude = 6.75155, - .elevation = 69, - }, - { - .code = "LFH278", - .name = "Noumea Pointe De L'artillerie", - .latitude = -22.2830555555556, - .longitude = 166.433611111111, - .elevation = 158, - }, - { - .code = "LFH279", - .name = "Noumea Caserne Normandie", - .latitude = -22.2263888888889, - .longitude = 166.486666666667, - .elevation = 99, - }, - { - .code = "LFH28", - .name = "Vichy Centre Hospitalier", - .latitude = 46.1236111111111, - .longitude = 3.43722222222222, - .elevation = 956, - }, - { - .code = "LFH288", - .name = "Argentan Centre Hospitalier", - .latitude = 48.7465277777778, - .longitude = -0.0178888888888889, - .elevation = 596, - }, - { - .code = "LFH29", - .name = "Blois Centre Hospitalier", - .latitude = 47.604675, - .longitude = 1.34245277777778, - .elevation = 355, - }, - { - .code = "LFH290", - .name = "Royan Centre Hospitalier", - .latitude = 45.6333333333333, - .longitude = -1.06083333333333, - .elevation = 81, - }, - { - .code = "LFH291", - .name = "Auch Centre Hospitalier", - .latitude = 43.6313888888889, - .longitude = 0.573333333333333, - .elevation = 597, - }, - { - .code = "LFH292", - .name = "Magny Cours Circuit Automobile", - .latitude = 46.8564111111111, - .longitude = 3.15426666666667, - .elevation = 751, - }, - { - .code = "LFH293", - .name = "Paray Le Monial Centre Hospitalier", - .latitude = 46.465, - .longitude = 4.10972222222222, - .elevation = 824, - }, - { - .code = "LFH294", - .name = "Auxerre Centre Hospitalier", - .latitude = 47.8044444444444, - .longitude = 3.55777777777778, - .elevation = 528, - }, - { - .code = "LFH296", - .name = "Sens Centre De Secours Principal", - .latitude = 48.1919444444444, - .longitude = 3.30638888888889, - .elevation = 266, - }, - { - .code = "LFH298", - .name = "Strasbourg N.H.C.", - .latitude = 48.5758333333333, - .longitude = 7.74055555555556, - .elevation = 540, - }, - { - .code = "LFH299", - .name = "Creil Centre Hospitalier Laennec", - .latitude = 49.2472222222222, - .longitude = 2.45805555555556, - .elevation = 238, - }, - { - .code = "LFH3", - .name = "Aix Les Bains Hotel Ariana", - .latitude = 45.6739638888889, - .longitude = 5.90888333333333, - .elevation = 810, - }, - { - .code = "LFH300", - .name = "Dunkerque Centre Hospitalier", - .latitude = 51.0375, - .longitude = 2.39666666666667, - .elevation = 55, - }, - { - .code = "LFH301", - .name = "Montceau Les Mines Centre Hospitalier", - .latitude = 46.65, - .longitude = 4.33388888888889, - .elevation = 958, - }, - { - .code = "LFH302", - .name = "Bale Mulhouse", - .latitude = 47.59, - .longitude = 7.52916666666667, - .elevation = 885, - }, - { - .code = "LFH303", - .name = "Bordeaux Merignac", - .latitude = 44.8286111111111, - .longitude = -0.715277777777778, - .elevation = 166, - }, - { - .code = "LFH304", - .name = "Bordeaux Pellegrin Centre Hospitalier", - .latitude = 44.8275, - .longitude = -0.604722222222222, - .elevation = 257, - }, - { - .code = "LFH305", - .name = "Bordeaux Robert Picque Hopital Militaire", - .latitude = 44.8, - .longitude = -0.574166666666667, - .elevation = 62, - }, - { - .code = "LFH306", - .name = "Cannes Mandelieu", - .latitude = 43.5463888888889, - .longitude = 6.95416666666667, - .elevation = 14, - }, - { - .code = "LFH307", - .name = "Cannes Quai Du Large", - .latitude = 43.545, - .longitude = 7.01722222222222, - .elevation = 10, - }, - { - .code = "LFH308", - .name = "Chalon Sur Saone Centre Hospitalier W. Morey", - .latitude = 46.7775, - .longitude = 4.84194444444444, - .elevation = 665, - }, - { - .code = "LFH309", - .name = "Chamonix Centre Hospitalier", - .latitude = 45.9144444444444, - .longitude = 6.86305555555556, - .elevation = 3399, - }, - { - .code = "LFH31", - .name = "Val Thorens", - .latitude = 45.2963888888889, - .longitude = 6.56555555555556, - .elevation = 6907, - }, - { - .code = "LFH312", - .name = "Chatellerault Centre Hospitalier", - .latitude = 46.8327777777778, - .longitude = 0.556666666666667, - .elevation = 277, - }, - { - .code = "LFH313", - .name = "Chiva (Foix)Centre Hospitalier", - .latitude = 43.025325, - .longitude = 1.61761666666667, - .elevation = 1151, - }, - { - .code = "LFH314", - .name = "Colmar Hopital Pasteur", - .latitude = 48.0738611111111, - .longitude = 7.33811111111111, - .elevation = 710, - }, - { - .code = "LFH315", - .name = "Coquelles Eurotunnel", - .latitude = 50.9180416666667, - .longitude = 1.79501944444444, - .elevation = 31, - }, - { - .code = "LFH32", - .name = "Montlucon Centre Hospitalier", - .latitude = 46.3416666666667, - .longitude = 2.60944444444444, - .elevation = 802, - }, - { - .code = "LFH322", - .name = "L'aigle Centre Hospitalier", - .latitude = 48.7680555555556, - .longitude = 0.611666666666667, - .elevation = 764, - }, - { - .code = "LFH323", - .name = "La Rochelle Centre Hospitalier", - .latitude = 46.1588888888889, - .longitude = -1.14305555555556, - .elevation = 49, - }, - { - .code = "LFH326", - .name = "Le Havre Centre Hospitalier", - .latitude = 49.5247222222222, - .longitude = 0.184722222222222, - .elevation = 57, - }, - { - .code = "LFH328", - .name = "Lorient Bretagne Sud Centre Hospitalier", - .latitude = 47.7536111111111, - .longitude = -3.35611111111111, - .elevation = 100, - }, - { - .code = "LFH329", - .name = "Lyon Bron", - .latitude = 45.7294444444444, - .longitude = 4.93888888888889, - .elevation = 659, - }, - { - .code = "LFH330", - .name = "Lyon Saint-Exupery", - .latitude = 45.7255555555556, - .longitude = 5.08111111111111, - .elevation = 821, - }, - { - .code = "LFH331", - .name = "Marseille Provence", - .latitude = 43.4366666666667, - .longitude = 5.215, - .elevation = 70, - }, - { - .code = "LFH333", - .name = "Montpellier Mediterranee", - .latitude = 43.5833333333333, - .longitude = 3.96138888888889, - .elevation = 17, - }, - { - .code = "LFH334", - .name = "Nantes Atlantique", - .latitude = 47.1569444444444, - .longitude = -1.60777777777778, - .elevation = 90, - }, - { - .code = "LFH335", - .name = "Nice Cote D'azur", - .latitude = 43.6652777777778, - .longitude = 7.215, - .elevation = 12, - }, - { - .code = "LFH336", - .name = "Macon Centre Hospitalier", - .latitude = 46.31445, - .longitude = 4.81230555555556, - .elevation = 727, - }, - { - .code = "LFH338", - .name = "Monaco Helistation", - .latitude = 43.7255555555556, - .longitude = 7.41916666666667, - .elevation = 19, - }, - { - .code = "LFH34", - .name = "Hopital Nord Franche Comte", - .latitude = 47.5761111111111, - .longitude = 6.87305555555556, - .elevation = 1263, - }, - { - .code = "LFH340", - .name = "Mulhouse Centre Hospitalier De Moenchsberg", - .latitude = 47.7253305555556, - .longitude = 7.34499166666667, - .elevation = 1081, - }, - { - .code = "LFH341", - .name = "Nancy Brabois Centre Hospitalier", - .latitude = 48.6447222222222, - .longitude = 6.15138888888889, - .elevation = 1335, - }, - { - .code = "LFH343", - .name = "Nevers Centre Hospitalier", - .latitude = 46.9813888888889, - .longitude = 3.12222222222222, - .elevation = 737, - }, - { - .code = "LFH344", - .name = "Oloron Sainte Marie Centre Hospitalier", - .latitude = 43.1958333333333, - .longitude = -0.617777777777778, - .elevation = 758, - }, - { - .code = "LFH345", - .name = "Orleans Centre Hospitalier", - .latitude = 47.8352777777778, - .longitude = 1.91944444444444, - .elevation = 424, - }, - { - .code = "LFH346", - .name = "Paris Centre Hospitalier La Pitie Salpetriere", - .latitude = 48.8371444444444, - .longitude = 2.36132777777778, - .elevation = 255, - }, - { - .code = "LFH347", - .name = "Paris Centre Hospitalier Lariboisiere", - .latitude = 48.8826388888889, - .longitude = 2.35442777777778, - .elevation = 262, - }, - { - .code = "LFH348", - .name = "Paris Issy Les Moulineaux", - .latitude = 48.8333, - .longitude = 2.27281666666667, - .elevation = 105, - }, - { - .code = "LFH349", - .name = "Paris Charles De Gaulle", - .latitude = 49.0097222222222, - .longitude = 2.54777777777778, - .elevation = 392, - }, - { - .code = "LFH350", - .name = "Paris Le Bourget", - .latitude = 48.9694444444444, - .longitude = 2.44138888888889, - .elevation = 220, - }, - { - .code = "LFH352", - .name = "Pau Pyrenees", - .latitude = 43.38, - .longitude = -0.418611111111111, - .elevation = 616, - }, - { - .code = "LFH353", - .name = "Pontoise Centre Hospitalier Rene Dubos", - .latitude = 49.0657027777778, - .longitude = 2.09776944444444, - .elevation = 266, - }, - { - .code = "LFH354", - .name = "Rennes Pont Chaillou Centre Hospitalier", - .latitude = 48.1230555555556, - .longitude = -1.69611111111111, - .elevation = 148, - }, - { - .code = "LFH355", - .name = "Rodez Bourran Centre Hospitalier", - .latitude = 44.3588888888889, - .longitude = 2.55194444444444, - .elevation = 1951, - }, - { - .code = "LFH358", - .name = "Saint Etienne Malacussy", - .latitude = 45.4240305555556, - .longitude = 4.37138333333333, - .elevation = 2148, - }, - { - .code = "LFH359", - .name = "Saint Pol Sur Ternoise Polyclinique Du Ternois", - .latitude = 50.3877777777778, - .longitude = 2.33555555555556, - .elevation = 417, - }, - { - .code = "LFH36", - .name = "Brest Amiraute", - .latitude = 48.3805555555556, - .longitude = -4.49166666666667, - .elevation = 0, - }, - { - .code = "LFH360", - .name = "Sarlat La Caneda Centre Hospitalier", - .latitude = 44.9000027777778, - .longitude = 1.22295555555556, - .elevation = 662, - }, - { - .code = "LFH361", - .name = "Semur En Auxois Centre Hospitalier", - .latitude = 47.4956416666667, - .longitude = 4.34453333333333, - .elevation = 957, - }, - { - .code = "LFH362", - .name = "Toulouse Purpan", - .latitude = 43.6130555555556, - .longitude = 1.4, - .elevation = 531, - }, - { - .code = "LFH363", - .name = "Toulouse Blagnac", - .latitude = 43.635, - .longitude = 1.36777777777778, - .elevation = 499, - }, - { - .code = "LFH364", - .name = "Toussus Le Noble", - .latitude = 48.7497222222222, - .longitude = 2.11111111111111, - .elevation = 538, - }, - { - .code = "LFH365", - .name = "Villacoublay Velizy", - .latitude = 48.7741666666667, - .longitude = 2.19166666666667, - .elevation = 585, - }, - { - .code = "LFH366", - .name = "Tours Trousseau Chu", - .latitude = 47.3489694444444, - .longitude = 0.709205555555556, - .elevation = 274, - }, - { - .code = "LFH368", - .name = "Dax Azur", - .latitude = 43.8069444444444, - .longitude = -1.25555555555556, - .elevation = 121, - }, - { - .code = "LFH369", - .name = "Dax Castets", - .latitude = 43.9166666666667, - .longitude = -1.15694444444444, - .elevation = 184, - }, - { - .code = "LFH37", - .name = "Brest Centre Hospitalier La Cavale Blanche", - .latitude = 48.4033333333333, - .longitude = -4.52944444444444, - .elevation = 121, - }, - { - .code = "LFH370", - .name = "Dax Herm", - .latitude = 43.8222222222222, - .longitude = -1.11111111111111, - .elevation = 253, - }, - { - .code = "LFH371", - .name = "Dax Pontonx", - .latitude = 43.7777777777778, - .longitude = -0.919444444444444, - .elevation = 53, - }, - { - .code = "LFH372", - .name = "Dax Tinon", - .latitude = 43.7333333333333, - .longitude = -1.17777777777778, - .elevation = 151, - }, - { - .code = "LFH374", - .name = "Charleville Mezieres Centre Hospitalier", - .latitude = 49.7626083333333, - .longitude = 4.69758333333333, - .elevation = 577, - }, - { - .code = "LFH375", - .name = "Nantes Quai Moncousu Centre Hospitalier", - .latitude = 47.2088888888889, - .longitude = -1.55444444444444, - .elevation = 77, - }, - { - .code = "LFH376", - .name = "Roanne Centre Hospitalier", - .latitude = 46.0426388888889, - .longitude = 4.07965277777778, - .elevation = 963, - }, - { - .code = "LFH377", - .name = "Toulon Sainte Anne Hopital Militaire", - .latitude = 43.1334555555556, - .longitude = 5.93019166666667, - .elevation = 226, - }, - { - .code = "LFH379", - .name = "Blaye Centre Hospitalier Saint Nicolas De Blaye", - .latitude = 45.1356944444444, - .longitude = -0.658916666666667, - .elevation = 81, - }, - { - .code = "LFH38", - .name = "Briancon", - .latitude = 44.906275, - .longitude = 6.63283333333333, - .elevation = 4372, - }, - { - .code = "LFH385", - .name = "Dole Centre Hospitalier", - .latitude = 47.0833333333333, - .longitude = 5.47277777777778, - .elevation = 868, - }, - { - .code = "LFH387", - .name = "Lons Le Saunier Centre Hospitalier", - .latitude = 46.6761111111111, - .longitude = 5.55, - .elevation = 896, - }, - { - .code = "LFH388", - .name = "Verneuil Sur Avre Centre Hospitalier", - .latitude = 48.7444444444444, - .longitude = 0.891666666666667, - .elevation = 597, - }, - { - .code = "LFH39", - .name = "Marseille Laveran Hopital Militaire", - .latitude = 43.3277777777778, - .longitude = 5.41555555555556, - .elevation = 353, - }, - { - .code = "LFH390", - .name = "Vendome Centre Hospitalier", - .latitude = 47.7941666666667, - .longitude = 1.06277777777778, - .elevation = 304, - }, - { - .code = "LFH391", - .name = "Nimes Caremeau Centre Hospitalier", - .latitude = 43.8238888888889, - .longitude = 4.32305555555556, - .elevation = 310, - }, - { - .code = "LFH393", - .name = "Selestat Centre Hospitalier", - .latitude = 48.2616666666667, - .longitude = 7.43222222222222, - .elevation = 587, - }, - { - .code = "LFH395", - .name = "Valenciennes Centre Hospitalier", - .latitude = 50.3608333333333, - .longitude = 3.49916666666667, - .elevation = 259, - }, - { - .code = "LFH396", - .name = "Arras Centre Hospitalier", - .latitude = 50.2962055555556, - .longitude = 2.75920833333333, - .elevation = 254, - }, - { - .code = "LFH397", - .name = "Bordeaux Haut Leveque Centre Hospitalier", - .latitude = 44.7852777777778, - .longitude = -0.660833333333333, - .elevation = 275, - }, - { - .code = "LFH398", - .name = "Issoudun Centre Hospitalier", - .latitude = 46.9594444444445, - .longitude = 1.99472222222222, - .elevation = 465, - }, - { - .code = "LFH399", - .name = "Gueret Centre Hospitalier", - .latitude = 46.1615555555556, - .longitude = 1.86866666666667, - .elevation = 1752, - }, - { - .code = "LFH4", - .name = "Albertville Centre Hospitalier", - .latitude = 45.6694388888889, - .longitude = 6.37, - .elevation = 1143, - }, - { - .code = "LFH40", - .name = "Caen Centre Hospitalier", - .latitude = 49.2036111111111, - .longitude = -0.3575, - .elevation = 283, - }, - { - .code = "LFH400", - .name = "Le Plessis Robinson Centre Chirurgical Marie Lannelongue", - .latitude = 48.7847222222222, - .longitude = 2.27416666666667, - .elevation = 382, - }, - { - .code = "LFH401", - .name = "Vesoul Centre Hospitalier", - .latitude = 47.6369444444444, - .longitude = 6.13722222222222, - .elevation = 741, - }, - { - .code = "LFH402", - .name = "Amboise Centre Hospitalier", - .latitude = 47.4080555555556, - .longitude = 0.981111111111111, - .elevation = 308, - }, - { - .code = "LFH403", - .name = "Loches Centre Hospitalier", - .latitude = 47.1305555555556, - .longitude = 1.00305555555556, - .elevation = 231, - }, - { - .code = "LFH404", - .name = "Bastia Centre Hospitalier", - .latitude = 42.6822222222222, - .longitude = 9.42833333333333, - .elevation = 443, - }, - { - .code = "LFH405", - .name = "Calvi Centre Hospitalier", - .latitude = 42.5497222222222, - .longitude = 8.76388888888889, - .elevation = 48, - }, - { - .code = "LFH406", - .name = "Porto-Vecchio", - .latitude = 41.58, - .longitude = 9.27694444444445, - .elevation = 30, - }, - { - .code = "LFH408", - .name = "Evreux Centre Hospitalier", - .latitude = 49.0311111111111, - .longitude = 1.11416666666667, - .elevation = 390, - }, - { - .code = "LFH409", - .name = "Langon Centre Hospitalier", - .latitude = 44.5447222222222, - .longitude = -0.243611111111111, - .elevation = 121, - }, - { - .code = "LFH410", - .name = "Gien Centre Hospitalier", - .latitude = 47.6902777777778, - .longitude = 2.63472222222222, - .elevation = 556, - }, - { - .code = "LFH411", - .name = "Saint Cyr L'ecole", - .latitude = 48.815, - .longitude = 2.06527777777778, - .elevation = 373, - }, - { - .code = "LFH412", - .name = "Digne Les Bains H1 Centre Hospitalier", - .latitude = 44.0705555555556, - .longitude = 6.16833333333333, - .elevation = 1975, - }, - { - .code = "LFH413", - .name = "Digne Les Bains H2 Centre Hospitalier", - .latitude = 44.0711111111111, - .longitude = 6.17194444444444, - .elevation = 1867, - }, - { - .code = "LFH414", - .name = "Saint Paul L'ermitage", - .latitude = -21.0678888888889, - .longitude = 55.2497222222222, - .elevation = 826, - }, - { - .code = "LFH416", - .name = "Lagny Sur Marne Centre Hospitalier", - .latitude = 48.8738888888889, - .longitude = 2.6975, - .elevation = 179, - }, - { - .code = "LFH417", - .name = "Lyon Groupement Hospitalier Est", - .latitude = 45.7477777777778, - .longitude = 4.9025, - .elevation = 818, - }, - { - .code = "LFH418", - .name = "Lyon Centre Hospitalier Sud", - .latitude = 45.7025, - .longitude = 4.8075, - .elevation = 753, - }, - { - .code = "LFH419", - .name = "Bourgoin Jallieu Centre Hospitalier Oudot", - .latitude = 45.5961111111111, - .longitude = 5.245, - .elevation = 822, - }, - { - .code = "LFH420", - .name = "Tignes Helistation Les Boisses", - .latitude = 45.4941666666667, - .longitude = 6.92972222222222, - .elevation = 5961, - }, - { - .code = "LFH421", - .name = "Saint Etienne Hopital Nord", - .latitude = 45.4822222222222, - .longitude = 4.36333333333333, - .elevation = 1507, - }, - { - .code = "LFH422", - .name = "Castres Hauterive Centre Hospitalier", - .latitude = 43.565, - .longitude = 2.26, - .elevation = 610, - }, - { - .code = "LFH423", - .name = "Eaubonne Hopital Simone Veil", - .latitude = 48.9999333333333, - .longitude = 2.27218333333333, - .elevation = 223, - }, - { - .code = "LFH424", - .name = "Narbonne Saint Crescent Centre Hospitalier", - .latitude = 43.1727888888889, - .longitude = 2.99456111111111, - .elevation = 30, - }, - { - .code = "LFH425", - .name = "Carpentras Centre Hospitalier", - .latitude = 44.0466666666667, - .longitude = 5.02583333333333, - .elevation = 285, - }, - { - .code = "LFH426", - .name = "Manosque Centre Hospitalier", - .latitude = 43.8280555555556, - .longitude = 5.80611111111111, - .elevation = 1081, - }, - { - .code = "LFH427", - .name = "Clermont Ferrand Saint Jacques", - .latitude = 45.7569833333333, - .longitude = 3.09186111111111, - .elevation = 1366, - }, - { - .code = "LFH428", - .name = "Clermont Ferrand Estaing", - .latitude = 45.7855555555556, - .longitude = 3.10972222222222, - .elevation = 1203, - }, - { - .code = "LFH430", - .name = "Martigues Centre Hospitalier", - .latitude = 43.4130555555556, - .longitude = 5.03888888888889, - .elevation = 178, - }, - { - .code = "LFH432", - .name = "Cannes Broussailles Hopital", - .latitude = 43.5641666666667, - .longitude = 7.00527777777778, - .elevation = 375, - }, - { - .code = "LFH433", - .name = "Alpes Leman Centre Hospitalier", - .latitude = 46.1419444444444, - .longitude = 6.32, - .elevation = 1532, - }, - { - .code = "LFH434", - .name = "Ales Centre Hospitalier", - .latitude = 44.1477777777778, - .longitude = 4.09555555555556, - .elevation = 552, - }, - { - .code = "LFH435", - .name = "Ger", - .latitude = 43.0508333333333, - .longitude = -0.0413888888888889, - .elevation = 1310, - }, - { - .code = "LFH436", - .name = "Montpellier Lapeyronie Chr", - .latitude = 43.6300055555556, - .longitude = 3.84965277777778, - .elevation = 150, - }, - { - .code = "LFH437", - .name = "Saint Quentin Centre Hospitalier", - .latitude = 49.8605555555556, - .longitude = 3.27166666666667, - .elevation = 380, - }, - { - .code = "LFH438", - .name = "Dijon Bocage Centre Hospitalier Universitaire", - .latitude = 47.3212833333333, - .longitude = 5.069075, - .elevation = 972, - }, - { - .code = "LFH439", - .name = "Amiens Centre Hospitalier Universitaire Nord", - .latitude = 49.9066666666667, - .longitude = 2.29583333333333, - .elevation = 161, - }, - { - .code = "LFH441", - .name = "Orange Centre Hospitalier", - .latitude = 44.1480555555556, - .longitude = 4.82194444444444, - .elevation = 155, - }, - { - .code = "LFH442", - .name = "Kremlin Bicetre Centre Hospitalier", - .latitude = 48.8094444444444, - .longitude = 2.35611111111111, - .elevation = 270, - }, - { - .code = "LFH443", - .name = "Besancon Chu Jean Minjoz", - .latitude = 47.2255694444444, - .longitude = 5.96447222222222, - .elevation = 940, - }, - { - .code = "LFH444", - .name = "Mende Centre Hospitalier", - .latitude = 44.5222222222222, - .longitude = 3.48916666666667, - .elevation = 2540, - }, - { - .code = "LFH445", - .name = "Perpignan Centre Hospitalier", - .latitude = 42.7261944444444, - .longitude = 2.8886, - .elevation = 190, - }, - { - .code = "LFH446", - .name = "Beauvais Centre Hospitalier", - .latitude = 49.4491666666667, - .longitude = 2.06833333333333, - .elevation = 304, - }, - { - .code = "LFH447", - .name = "Corbeil-Essonnes Centre Hospitalier Sud Francilien", - .latitude = 48.6202777777778, - .longitude = 2.45722222222222, - .elevation = 338, - }, - { - .code = "LFH448", - .name = "Biarritz Pays Basque", - .latitude = 43.4683333333333, - .longitude = -1.53111111111111, - .elevation = 245, - }, - { - .code = "LFH449", - .name = "Toulon Sainte Musse Hopital", - .latitude = 43.1244027777778, - .longitude = 5.97496111111111, - .elevation = 165, - }, - { - .code = "LFH45", - .name = "Castres Centre Hospitalier", - .latitude = 43.6038444444444, - .longitude = 2.23920277777778, - .elevation = 642, - }, - { - .code = "LFH450", - .name = "Tonnerre Centre Hospitalier", - .latitude = 47.8555555555556, - .longitude = 3.97944444444444, - .elevation = 456, - }, - { - .code = "LFH451", - .name = "Versailles Centre Hospitalier", - .latitude = 48.8308333333333, - .longitude = 2.12777777777778, - .elevation = 492, - }, - { - .code = "LFH452", - .name = "Dieppe Centre Hospitalier", - .latitude = 49.9177777777778, - .longitude = 1.08055555555556, - .elevation = 69, - }, - { - .code = "LFH453", - .name = "Metz Mercy Centre Hospitalier", - .latitude = 49.0841666666667, - .longitude = 6.24222222222222, - .elevation = 868, - }, - { - .code = "LFH454", - .name = "Arcachon Pole Sante", - .latitude = 44.6125, - .longitude = -1.11388888888889, - .elevation = 46, - }, - { - .code = "LFH455", - .name = "Melun Centre Hospitalier Marc Jacquet", - .latitude = 48.5575, - .longitude = 2.64166666666667, - .elevation = 338, - }, - { - .code = "LFH456", - .name = "Sete Helistation Des Hopitaux Du Bassin De Thau", - .latitude = 43.4077777777778, - .longitude = 3.66972222222222, - .elevation = 136, - }, - { - .code = "LFH457", - .name = "Bagnols Sur Ceze Centre Hospitalier", - .latitude = 44.1583333333333, - .longitude = 4.61555555555555, - .elevation = 285, - }, - { - .code = "LFH458", - .name = "Marne La Vallee Centre Hospitalier", - .latitude = 48.8486111111111, - .longitude = 2.76972222222222, - .elevation = 412, - }, - { - .code = "LFH459", - .name = "Calais Centre Hospitalier", - .latitude = 50.9412833333333, - .longitude = 1.88948055555556, - .elevation = 11, - }, - { - .code = "LFH46", - .name = "Cerbere", - .latitude = 42.4589083333333, - .longitude = 3.15991666666667, - .elevation = 50, - }, - { - .code = "LFH460", - .name = "Le Blanc Centre Hospitalier", - .latitude = 46.6338888888889, - .longitude = 1.05861111111111, - .elevation = 302, - }, - { - .code = "LFH461", - .name = "Nice Hopital Pasteur 2", - .latitude = 43.7247222222222, - .longitude = 7.2825, - .elevation = 258, - }, - { - .code = "LFH462", - .name = "Aurillac Centre Hospitalier", - .latitude = 44.9266666666667, - .longitude = 2.43805555555556, - .elevation = 2146, - }, - { - .code = "LFH463", - .name = "Bourg En Bresse Centre Hospitalier", - .latitude = 46.2247222222222, - .longitude = 5.20972222222222, - .elevation = 814, - }, - { - .code = "LFH464", - .name = "Le Mans Centre Hospitalier", - .latitude = 48.0167333333333, - .longitude = 0.173277777777778, - .elevation = 225, - }, - { - .code = "LFH465", - .name = "Ambert Centre Hospitalier", - .latitude = 45.5538888888889, - .longitude = 3.74138888888889, - .elevation = 1762, - }, - { - .code = "LFH466", - .name = "Savoie Helicopteres", - .latitude = 46.0711111111111, - .longitude = 6.51777777777778, - .elevation = 1535, - }, - { - .code = "LFH467", - .name = "Laon Semilly Centre Hospitalier", - .latitude = 49.55, - .longitude = 3.59722222222222, - .elevation = 233, - }, - { - .code = "LFH468", - .name = "Monaco Centre Hospitalier Princesse Grace", - .latitude = 43.7293861111111, - .longitude = 7.41018611111111, - .elevation = 259, - }, - { - .code = "LFH469", - .name = "Nord Deux-Sevres Centre Hospitalier", - .latitude = 46.8315138888889, - .longitude = -0.386, - .elevation = 567, - }, - { - .code = "LFH470", - .name = "Metz Frescaty", - .latitude = 49.0705555555556, - .longitude = 6.12611111111111, - .elevation = 630, - }, - { - .code = "LFH471", - .name = "Colmar Meyenheim", - .latitude = 47.9191666666667, - .longitude = 7.4025, - .elevation = 660, - }, - { - .code = "LFH5", - .name = "Albertville Crs Alpes", - .latitude = 45.6568944444444, - .longitude = 6.37603611111111, - .elevation = 1084, - }, - { - .code = "LFH52", - .name = "Chambery Centre Hospitalier", - .latitude = 45.5630555555556, - .longitude = 5.91194444444444, - .elevation = 1020, - }, - { - .code = "LFH53", - .name = "Chamonix Croix De Lognan", - .latitude = 45.97, - .longitude = 6.94444444444444, - .elevation = 6368, - }, - { - .code = "LFH56", - .name = "Chamonix Securite", - .latitude = 45.9389194444444, - .longitude = 6.89581111111111, - .elevation = 3532, - }, - { - .code = "LFH6", - .name = "Echirolles Clinique Des Cedres", - .latitude = 45.1475, - .longitude = 5.72333333333333, - .elevation = 799, - }, - { - .code = "LFH60", - .name = "Chauny Centre Hospitalier", - .latitude = 49.6261111111111, - .longitude = 3.2375, - .elevation = 180, - }, - { - .code = "LFH62", - .name = "Cherbourg Arsenal-Premar", - .latitude = 49.6538888888889, - .longitude = -1.64, - .elevation = 26, - }, - { - .code = "LFH64", - .name = "Cholet Centre Hospitalier", - .latitude = 47.0414138888889, - .longitude = -0.897361111111111, - .elevation = 352, - }, - { - .code = "LFH66", - .name = "Clamart Hopital D'instruction Des Armees De Percy", - .latitude = 48.8142972222222, - .longitude = 2.25393333333333, - .elevation = 333, - }, - { - .code = "LFH69", - .name = "Compiegne Centre Hospitalier", - .latitude = 49.3897222222222, - .longitude = 2.79555555555556, - .elevation = 108, - }, - { - .code = "LFH7", - .name = "Alencon Centre Hospitalier", - .latitude = 48.4241666666667, - .longitude = 0.0825, - .elevation = 435, - }, - { - .code = "LFH75", - .name = "Creteil Centre Hospitalier Henri Mondor", - .latitude = 48.7987583333333, - .longitude = 2.45348333333333, - .elevation = 160, - }, - { - .code = "LFH78", - .name = "Dax Centre Hospitalier", - .latitude = 43.7125, - .longitude = -1.04027777777778, - .elevation = 31, - }, - { - .code = "LFH8", - .name = "Amiens Centre Hospitalier Universitaire Sud", - .latitude = 49.8761111111111, - .longitude = 2.2575, - .elevation = 250, - }, - { - .code = "LFH81", - .name = "Divonne Hotel Du Chateau", - .latitude = 46.3580083333333, - .longitude = 6.13258333333333, - .elevation = 1678, - }, - { - .code = "LFH84", - .name = "Douai Usine Renault", - .latitude = 50.3616666666667, - .longitude = 3.03666666666667, - .elevation = 95, - }, - { - .code = "LFH9", - .name = "Saint Flour Centre Hospitalier", - .latitude = 45.0336111111111, - .longitude = 3.08666666666667, - .elevation = 2963, - }, - { - .code = "LFH94", - .name = "Flamanville", - .latitude = 49.5333333333333, - .longitude = -1.88333333333333, - .elevation = 269, - }, - { - .code = "LFH95", - .name = "Flins", - .latitude = 48.9819444444444, - .longitude = 1.86388888888889, - .elevation = 82, - }, - { - .code = "LFH98", - .name = "Gap Hopital", - .latitude = 44.5572222222222, - .longitude = 6.07333611111111, - .elevation = 2503, - }, - { - .code = "LFH99", - .name = "Garches Hopital Raymond Poincare", - .latitude = 48.8393222222222, - .longitude = 2.17036666666667, - .elevation = 446, - }, - { - .code = "LFHA", - .name = "Issoire Le Broc", - .latitude = 45.5138888888889, - .longitude = 3.26611111111111, - .elevation = 1240, - }, - { - .code = "LFHC", - .name = "Perouges Meximieux", - .latitude = 45.8686111111111, - .longitude = 5.18611111111111, - .elevation = 703, - }, - { - .code = "LFHD", - .name = "Pierrelatte", - .latitude = 44.3977777777778, - .longitude = 4.71694444444444, - .elevation = 195, - }, - { - .code = "LFHE", - .name = "Romans Saint Paul", - .latitude = 45.0647222222222, - .longitude = 5.10138888888889, - .elevation = 595, - }, - { - .code = "LFHF", - .name = "Ruoms", - .latitude = 44.4447222222222, - .longitude = 4.33277777777778, - .elevation = 353, - }, - { - .code = "LFHG", - .name = "Saint Chamond L'horme", - .latitude = 45.4919444444444, - .longitude = 4.53444444444444, - .elevation = 1307, - }, - { - .code = "LFHH", - .name = "Vienne Reventin", - .latitude = 45.4627777777778, - .longitude = 4.82777777777778, - .elevation = 720, - }, - { - .code = "LFHI", - .name = "Morestel", - .latitude = 45.6869444444444, - .longitude = 5.4525, - .elevation = 803, - }, - { - .code = "LFHJ", - .name = "Lyon Corbas", - .latitude = 45.6527777777778, - .longitude = 4.91222222222222, - .elevation = 652, - }, - { - .code = "LFHL", - .name = "Langogne Lesperon", - .latitude = 44.7055555555556, - .longitude = 3.88722222222222, - .elevation = 3339, - }, - { - .code = "LFHM", - .name = "Megeve", - .latitude = 45.8244444444444, - .longitude = 6.64833333333333, - .elevation = 4830, - }, - { - .code = "LFHN", - .name = "Bellegarde Vouvray", - .latitude = 46.1233333333333, - .longitude = 5.80472222222222, - .elevation = 1626, - }, - { - .code = "LFHO", - .name = "Aubenas Ardeche Meridionale", - .latitude = 44.5394194444444, - .longitude = 4.37173333333333, - .elevation = 923, - }, - { - .code = "LFHP", - .name = "Le Puy Loudes", - .latitude = 45.0796555555556, - .longitude = 3.76344166666667, - .elevation = 2731, - }, - { - .code = "LFHQ", - .name = "Saint Flour Coltines", - .latitude = 45.0749194444444, - .longitude = 2.99263611111111, - .elevation = 3218, - }, - { - .code = "LFHR", - .name = "Brioude Beaumont", - .latitude = 45.3238888888889, - .longitude = 3.35833333333333, - .elevation = 1487, - }, - { - .code = "LFHS", - .name = "Bourg Ceyzeriat", - .latitude = 46.2056194444444, - .longitude = 5.29179444444444, - .elevation = 857, - }, - { - .code = "LFHT", - .name = "Ambert Le Poyet", - .latitude = 45.5155555555556, - .longitude = 3.745, - .elevation = 1848, - }, - { - .code = "LFHU", - .name = "L'alpe D'huez", - .latitude = 45.0875, - .longitude = 6.08361111111111, - .elevation = 6103, - }, - { - .code = "LFHV", - .name = "Villefranche Tarare", - .latitude = 45.9199833333333, - .longitude = 4.63493055555556, - .elevation = 1076, - }, - { - .code = "LFHW", - .name = "Belleville Villie Morgon", - .latitude = 46.1411111111111, - .longitude = 4.71388888888889, - .elevation = 705, - }, - { - .code = "LFHX", - .name = "Lapalisse Perigny", - .latitude = 46.2530555555556, - .longitude = 3.5875, - .elevation = 1045, - }, - { - .code = "LFHY", - .name = "Moulins Montbeugny", - .latitude = 46.5343833333333, - .longitude = 3.42160555555556, - .elevation = 915, - }, - { - .code = "LFHZ", - .name = "Sallanches Mont Blanc", - .latitude = 45.95, - .longitude = 6.63888888888889, - .elevation = 1756, - }, - { - .code = "LFIB", - .name = "Belves Saint Pardoux", - .latitude = 44.7825, - .longitude = 0.958888888888889, - .elevation = 791, - }, - { - .code = "LFID", - .name = "Condom Valence Sur Baise", - .latitude = 43.9091666666667, - .longitude = 0.386111111111111, - .elevation = 444, - }, - { - .code = "LFIF", - .name = "Saint Affrique Belmont", - .latitude = 43.8227777777778, - .longitude = 2.74722222222222, - .elevation = 1686, - }, - { - .code = "LFIG", - .name = "Cassagnes Begonhes", - .latitude = 44.1783333333333, - .longitude = 2.51777777777778, - .elevation = 2025, - }, - { - .code = "LFIH", - .name = "Chalais", - .latitude = 45.2670777777778, - .longitude = 0.0158333333333333, - .elevation = 299, - }, - { - .code = "LFIK", - .name = "Riberac-Tourette", - .latitude = 45.2394444444444, - .longitude = 0.265833333333333, - .elevation = 353, - }, - { - .code = "LFIL", - .name = "Rion Des Landes", - .latitude = 43.9158333333333, - .longitude = -0.949166666666667, - .elevation = 256, - }, - { - .code = "LFIM", - .name = "Saint Gaudens Montrejeau", - .latitude = 43.1075, - .longitude = 0.619166666666667, - .elevation = 1320, - }, - { - .code = "LFIP", - .name = "Peyresourde Balestas", - .latitude = 42.7969444444444, - .longitude = 0.433888888888889, - .elevation = 5193, - }, - { - .code = "LFIR", - .name = "Revel Montgey", - .latitude = 43.4802777777778, - .longitude = 1.97888888888889, - .elevation = 643, - }, - { - .code = "LFIS", - .name = "Saint Inglevert Les Deux Caps", - .latitude = 50.8825, - .longitude = 1.73611111111111, - .elevation = 443, - }, - { - .code = "LFIT", - .name = "Toulouse Bourg Saint Bernard", - .latitude = 43.6111111111111, - .longitude = 1.72416666666667, - .elevation = 526, - }, - { - .code = "LFIV", - .name = "Vendays Montalivet", - .latitude = 45.3805555555556, - .longitude = -1.11583333333333, - .elevation = 16, - }, - { - .code = "LFIX", - .name = "Itxassou", - .latitude = 43.3375, - .longitude = -1.42222222222222, - .elevation = 607, - }, - { - .code = "LFIY", - .name = "Saint Jean D'angely Saint Denis Du Pin", - .latitude = 45.9652027777778, - .longitude = -0.524358333333333, - .elevation = 245, - }, - { - .code = "LFJA", - .name = "Chaumont Semoutiers", - .latitude = 48.0916666666667, - .longitude = 5.05, - .elevation = 1001, - }, - { - .code = "LFJB", - .name = "Mauleon", - .latitude = 46.9030555555556, - .longitude = -0.6975, - .elevation = 568, - }, - { - .code = "LFJC", - .name = "Clamecy", - .latitude = 47.4375, - .longitude = 3.5075, - .elevation = 714, - }, - { - .code = "LFJD", - .name = "Corlier", - .latitude = 46.0397222222222, - .longitude = 5.49611111111111, - .elevation = 2770, - }, - { - .code = "LFJE", - .name = "La Motte Chalancon", - .latitude = 44.4966666666667, - .longitude = 5.40333333333333, - .elevation = 2883, - }, - { - .code = "LFJF", - .name = "Aubenasson", - .latitude = 44.6952777777778, - .longitude = 5.15388888888889, - .elevation = 807, - }, - { - .code = "LFJH", - .name = "Cazeres Palaminy", - .latitude = 43.2008333333333, - .longitude = 1.05, - .elevation = 816, - }, - { - .code = "LFJI", - .name = "Marennes", - .latitude = 45.8238888888889, - .longitude = -1.07722222222222, - .elevation = 29, - }, - { - .code = "LFJL", - .name = "Metz Nancy Lorraine", - .latitude = 48.9782805555556, - .longitude = 6.24653055555556, - .elevation = 870, - }, - { - .code = "LFJR", - .name = "Angers Marce", - .latitude = 47.5602111111111, - .longitude = -0.312127777777778, - .elevation = 194, - }, - { - .code = "LFJS", - .name = "Soissons Courmelles", - .latitude = 49.345, - .longitude = 3.28305555555556, - .elevation = 518, - }, - { - .code = "LFJT", - .name = "Tours Le Louroux", - .latitude = 47.15, - .longitude = 0.712777777777778, - .elevation = 413, - }, - { - .code = "LFJU", - .name = "Lurcy Levis", - .latitude = 46.7122222222222, - .longitude = 2.94472222222222, - .elevation = 747, - }, - { - .code = "LFJV", - .name = "Lasclaveries", - .latitude = 43.4252777777778, - .longitude = -0.286944444444444, - .elevation = 843, - }, - { - .code = "LFJY", - .name = "Chambley", - .latitude = 49.0254694444444, - .longitude = 5.87609166666667, - .elevation = 866, - }, - { - .code = "LFKA", - .name = "Albertville", - .latitude = 45.6263888888889, - .longitude = 6.32888888888889, - .elevation = 1035, - }, - { - .code = "LFKB", - .name = "Bastia Poretta", - .latitude = 42.55, - .longitude = 9.48484722222222, - .elevation = 26, - }, - { - .code = "LFKC", - .name = "Calvi Sainte Catherine", - .latitude = 42.5243555555556, - .longitude = 8.79301111111111, - .elevation = 210, - }, - { - .code = "LFKD", - .name = "Sollieres Sardieres", - .latitude = 45.2538888888889, - .longitude = 6.80111111111111, - .elevation = 4255, - }, - { - .code = "LFKE", - .name = "Saint Jean En Royans", - .latitude = 45.0263888888889, - .longitude = 5.30916666666667, - .elevation = 872, - }, - { - .code = "LFKF", - .name = "Figari Sud Corse", - .latitude = 41.5021083333333, - .longitude = 9.09674722222222, - .elevation = 87, - }, - { - .code = "LFKG", - .name = "Ghisonaccia Alzitone", - .latitude = 42.0544444444444, - .longitude = 9.40027777777778, - .elevation = 177, - }, - { - .code = "LFKH", - .name = "Saint Jean D'avelanne", - .latitude = 45.5158333333333, - .longitude = 5.67944444444444, - .elevation = 964, - }, - { - .code = "LFKJ", - .name = "Ajaccio Napoleon Bonaparte", - .latitude = 41.9238972222222, - .longitude = 8.80243611111111, - .elevation = 19, - }, - { - .code = "LFKK", - .name = "Montmeilleur", - .latitude = 44.7936111111111, - .longitude = 5.76166666666667, - .elevation = 2992, - }, - { - .code = "LFKL", - .name = "Lyon Brindas", - .latitude = 45.71065, - .longitude = 4.69665, - .elevation = 1040, - }, - { - .code = "LFKM", - .name = "Saint Galmier", - .latitude = 45.6063888888889, - .longitude = 4.305, - .elevation = 1269, - }, - { - .code = "LFKO", - .name = "Propriano", - .latitude = 41.6602777777778, - .longitude = 8.89388888888889, - .elevation = 16, - }, - { - .code = "LFKP", - .name = "La Tour Du Pin Cessieu", - .latitude = 45.5588888888889, - .longitude = 5.38388888888889, - .elevation = 1053, - }, - { - .code = "LFKR", - .name = "Saint Remy De Maurienne", - .latitude = 45.3750333333333, - .longitude = 6.27781388888889, - .elevation = 1399, - }, - { - .code = "LFKS", - .name = "Solenzara", - .latitude = 41.9262888888889, - .longitude = 9.40530277777778, - .elevation = 29, - }, - { - .code = "LFKT", - .name = "Corte", - .latitude = 42.2902777777778, - .longitude = 9.1925, - .elevation = 1130, - }, - { - .code = "LFKX", - .name = "Meribel Robert Merloz", - .latitude = 45.4075, - .longitude = 6.5775, - .elevation = 5639, - }, - { - .code = "LFKY", - .name = "Belley-Peyrieu", - .latitude = 45.6938888888889, - .longitude = 5.69166666666667, - .elevation = 739, - }, - { - .code = "LFLA", - .name = "Auxerre Branches", - .latitude = 47.8463277777778, - .longitude = 3.49657777777778, - .elevation = 523, - }, - { - .code = "LFLB", - .name = "Chambery Aix Les Bains", - .latitude = 45.6392722222222, - .longitude = 5.88012222222222, - .elevation = 779, - }, - { - .code = "LFLC", - .name = "Clermont Ferrand Auvergne", - .latitude = 45.7859722222222, - .longitude = 3.16245, - .elevation = 1092, - }, - { - .code = "LFLD", - .name = "Bourges", - .latitude = 47.0607861111111, - .longitude = 2.37008333333333, - .elevation = 529, - }, - { - .code = "LFLE", - .name = "Chambery Challes Les Eaux", - .latitude = 45.5605555555556, - .longitude = 5.97583333333333, - .elevation = 973, - }, - { - .code = "LFLG", - .name = "Grenoble Le Versoud", - .latitude = 45.2180555555556, - .longitude = 5.84861111111111, - .elevation = 724, - }, - { - .code = "LFLH", - .name = "Chalon Champforgeuil", - .latitude = 46.828275, - .longitude = 4.81705833333333, - .elevation = 623, - }, - { - .code = "LFLI", - .name = "Annemasse", - .latitude = 46.1919444444444, - .longitude = 6.26833333333333, - .elevation = 1620, - }, - { - .code = "LFLJ", - .name = "Courchevel", - .latitude = 45.3958333333333, - .longitude = 6.6325, - .elevation = 6583, - }, - { - .code = "LFLK", - .name = "Oyonnax Arbent", - .latitude = 46.2786111111111, - .longitude = 5.66638888888889, - .elevation = 1755, - }, - { - .code = "LFLL", - .name = "Lyon Saint Exupery", - .latitude = 45.7256388888889, - .longitude = 5.08110555555556, - .elevation = 821, - }, - { - .code = "LFLM", - .name = "Macon Charnay", - .latitude = 46.2959222222222, - .longitude = 4.79585833333333, - .elevation = 729, - }, - { - .code = "LFLN", - .name = "Saint Yan", - .latitude = 46.4064916666667, - .longitude = 4.02109722222222, - .elevation = 796, - }, - { - .code = "LFLO", - .name = "Roanne", - .latitude = 46.0527777777778, - .longitude = 3.99972222222222, - .elevation = 1106, - }, - { - .code = "LFLP", - .name = "Annecy Meythet", - .latitude = 45.930775, - .longitude = 6.10628888888889, - .elevation = 1521, - }, - { - .code = "LFLQ", - .name = "Montelimar Ancone", - .latitude = 44.5802777777778, - .longitude = 4.73916666666667, - .elevation = 241, - }, - { - .code = "LFLR", - .name = "Saint Rambert D'albon", - .latitude = 45.255, - .longitude = 4.82472222222222, - .elevation = 509, - }, - { - .code = "LFLS", - .name = "Grenoble Isere", - .latitude = 45.3629361111111, - .longitude = 5.33266388888889, - .elevation = 1302, - }, - { - .code = "LFLT", - .name = "Montlucon Domerat", - .latitude = 46.3527777777778, - .longitude = 2.57055555555556, - .elevation = 771, - }, - { - .code = "LFLU", - .name = "Valence Chabeuil", - .latitude = 44.9155583333333, - .longitude = 4.96874444444444, - .elevation = 525, - }, - { - .code = "LFLV", - .name = "Vichy Charmeil", - .latitude = 46.1717833333333, - .longitude = 3.40403333333333, - .elevation = 817, - }, - { - .code = "LFLW", - .name = "Aurillac", - .latitude = 44.8975833333333, - .longitude = 2.41671944444444, - .elevation = 2096, - }, - { - .code = "LFLX", - .name = "Chateauroux Deols", - .latitude = 46.8603138888889, - .longitude = 1.721125, - .elevation = 529, - }, - { - .code = "LFLY", - .name = "Lyon Bron", - .latitude = 45.7295194444444, - .longitude = 4.93884444444444, - .elevation = 659, - }, - { - .code = "LFLZ", - .name = "Feurs Chambeon", - .latitude = 45.7066666666667, - .longitude = 4.19694444444445, - .elevation = 1095, - }, - { - .code = "LFMA", - .name = "Aix Les Milles", - .latitude = 43.5052777777778, - .longitude = 5.36722222222222, - .elevation = 368, - }, - { - .code = "LFMC", - .name = "Le Luc Le Cannet", - .latitude = 43.3847222222222, - .longitude = 6.38694444444444, - .elevation = 265, - }, - { - .code = "LFMD", - .name = "Cannes Mandelieu", - .latitude = 43.5463888888889, - .longitude = 6.95416666666667, - .elevation = 14, - }, - { - .code = "LFME", - .name = "Nimes Courbessac", - .latitude = 43.8530555555556, - .longitude = 4.41444444444444, - .elevation = 197, - }, - { - .code = "LFMF", - .name = "Fayence", - .latitude = 43.6080555555556, - .longitude = 6.70166666666667, - .elevation = 738, - }, - { - .code = "LFMG", - .name = "Montagne Noire", - .latitude = 43.4063888888889, - .longitude = 1.98916666666667, - .elevation = 1468, - }, - { - .code = "LFMH", - .name = "Saint Etienne Loire", - .latitude = 45.53405, - .longitude = 4.29731111111111, - .elevation = 1325, - }, - { - .code = "LFMI", - .name = "Istres Le Tube", - .latitude = 43.5223944444444, - .longitude = 4.92423611111111, - .elevation = 82, - }, - { - .code = "LFMK", - .name = "Carcassonne Salvaza", - .latitude = 43.2158166666667, - .longitude = 2.30854444444444, - .elevation = 434, - }, - { - .code = "LFML", - .name = "Marseille Provence", - .latitude = 43.4366333333333, - .longitude = 5.21511944444444, - .elevation = 70, - }, - { - .code = "LFMN", - .name = "Nice Cote D'azur", - .latitude = 43.6654055555556, - .longitude = 7.21498333333333, - .elevation = 12, - }, - { - .code = "LFMO", - .name = "Orange Caritat", - .latitude = 44.1400888888889, - .longitude = 4.86858055555556, - .elevation = 197, - }, - { - .code = "LFMP", - .name = "Perpignan Rivesaltes", - .latitude = 42.7408333333333, - .longitude = 2.86972222222222, - .elevation = 144, - }, - { - .code = "LFMQ", - .name = "Le Castellet", - .latitude = 43.2522222222222, - .longitude = 5.78611111111111, - .elevation = 1391, - }, - { - .code = "LFMR", - .name = "Barcelonnette Saint Pons", - .latitude = 44.3872222222222, - .longitude = 6.60916666666667, - .elevation = 3714, - }, - { - .code = "LFMS", - .name = "Ales Cevennes", - .latitude = 44.0727333333333, - .longitude = 4.14291944444444, - .elevation = 668, - }, - { - .code = "LFMT", - .name = "Montpellier Mediterranee", - .latitude = 43.5832611111111, - .longitude = 3.96137777777778, - .elevation = 17, - }, - { - .code = "LFMU", - .name = "Beziers Vias", - .latitude = 43.3234277777778, - .longitude = 3.35339722222222, - .elevation = 56, - }, - { - .code = "LFMV", - .name = "Avignon Caumont", - .latitude = 43.9065805555556, - .longitude = 4.90202777777778, - .elevation = 124, - }, - { - .code = "LFMW", - .name = "Castelnaudary Villeneuve", - .latitude = 43.3111111111111, - .longitude = 1.92, - .elevation = 553, - }, - { - .code = "LFMX", - .name = "Chateau Arnoux Saint Auban", - .latitude = 44.0586111111111, - .longitude = 5.99083333333333, - .elevation = 1507, - }, - { - .code = "LFMY", - .name = "Salon De Provence", - .latitude = 43.6029083333333, - .longitude = 5.10816666666667, - .elevation = 197, - }, - { - .code = "LFMZ", - .name = "Lezignan Corbieres", - .latitude = 43.175, - .longitude = 2.73277777777778, - .elevation = 204, - }, - { - .code = "LFNA", - .name = "Gap Tallard", - .latitude = 44.4538888888889, - .longitude = 6.03666666666667, - .elevation = 1966, - }, - { - .code = "LFNB", - .name = "Mende Brenoux", - .latitude = 44.5040805555556, - .longitude = 3.52763333333333, - .elevation = 3362, - }, - { - .code = "LFNC", - .name = "Mont Dauphin Saint Crepin", - .latitude = 44.7005555555556, - .longitude = 6.59916666666667, - .elevation = 2963, - }, - { - .code = "LFNE", - .name = "Salon Eyguieres", - .latitude = 43.6575, - .longitude = 5.01277777777778, - .elevation = 247, - }, - { - .code = "LFNF", - .name = "Vinon", - .latitude = 43.7363888888889, - .longitude = 5.78305555555556, - .elevation = 903, - }, - { - .code = "LFNG", - .name = "Montpellier Candillargues", - .latitude = 43.6101722222222, - .longitude = 4.07016111111111, - .elevation = 5, - }, - { - .code = "LFNH", - .name = "Carpentras", - .latitude = 44.0225, - .longitude = 5.09, - .elevation = 388, - }, - { - .code = "LFNJ", - .name = "Aspres Sur Buech", - .latitude = 44.5177777777778, - .longitude = 5.73611111111111, - .elevation = 2727, - }, - { - .code = "LFNL", - .name = "Saint Martin De Londres", - .latitude = 43.8002777777778, - .longitude = 3.78166666666667, - .elevation = 602, - }, - { - .code = "LFNN", - .name = "Narbonne", - .latitude = 43.1941666666667, - .longitude = 3.05166666666667, - .elevation = 10, - }, - { - .code = "LFNO", - .name = "Florac Sainte Enimie", - .latitude = 44.2855555555556, - .longitude = 3.46555555555556, - .elevation = 3055, - }, - { - .code = "LFNQ", - .name = "La Llagonne La Quillane", - .latitude = 42.5434611111111, - .longitude = 2.12002222222222, - .elevation = 5612, - }, - { - .code = "LFNR", - .name = "Berre La Fare", - .latitude = 43.5366666666667, - .longitude = 5.1775, - .elevation = 108, - }, - { - .code = "LFNS", - .name = "Sisteron Vaumeilh", - .latitude = 44.2866666666667, - .longitude = 5.92916666666667, - .elevation = 1778, - }, - { - .code = "LFNT", - .name = "Avignon Pujaut", - .latitude = 43.9961111111111, - .longitude = 4.75444444444444, - .elevation = 146, - }, - { - .code = "LFNU", - .name = "Uzes", - .latitude = 44.0834722222222, - .longitude = 4.39383333333333, - .elevation = 884, - }, - { - .code = "LFNV", - .name = "Valreas Visan", - .latitude = 44.3358333333333, - .longitude = 4.90694444444444, - .elevation = 472, - }, - { - .code = "LFNW", - .name = "Puivert", - .latitude = 42.9102777777778, - .longitude = 2.05472222222222, - .elevation = 1610, - }, - { - .code = "LFNX", - .name = "Bedarieux La Tour Sur Orb", - .latitude = 43.6397222222222, - .longitude = 3.14472222222222, - .elevation = 1247, - }, - { - .code = "LFNZ", - .name = "Le Mazet De Romanin", - .latitude = 43.7708333333333, - .longitude = 4.89444444444444, - .elevation = 395, - }, - { - .code = "LFOA", - .name = "Avord", - .latitude = 47.0569444444444, - .longitude = 2.63888888888889, - .elevation = 578, - }, - { - .code = "LFOB", - .name = "Beauvais Tille", - .latitude = 49.4544222222222, - .longitude = 2.11281388888889, - .elevation = 359, - }, - { - .code = "LFOC", - .name = "Chateaudun", - .latitude = 48.057875, - .longitude = 1.37944166666667, - .elevation = 433, - }, - { - .code = "LFOD", - .name = "Saumur Saint Florent", - .latitude = 47.2567305555556, - .longitude = -0.113552777777778, - .elevation = 269, - }, - { - .code = "LFOE", - .name = "Evreux Fauville", - .latitude = 49.0286111111111, - .longitude = 1.22, - .elevation = 464, - }, - { - .code = "LFOF", - .name = "Alencon Valframbert", - .latitude = 48.4466666666667, - .longitude = 0.108333333333333, - .elevation = 476, - }, - { - .code = "LFOG", - .name = "Flers Saint Paul", - .latitude = 48.7497222222222, - .longitude = -0.594722222222222, - .elevation = 663, - }, - { - .code = "LFOH", - .name = "Le Havre Octeville", - .latitude = 49.5338472222222, - .longitude = 0.0881194444444444, - .elevation = 313, - }, - { - .code = "LFOI", - .name = "Abbeville", - .latitude = 50.1422222222222, - .longitude = 1.83111111111111, - .elevation = 220, - }, - { - .code = "LFOJ", - .name = "Orleans Bricy", - .latitude = 47.9877777777778, - .longitude = 1.76055555555556, - .elevation = 412, - }, - { - .code = "LFOK", - .name = "Chalons Vatry", - .latitude = 48.773325, - .longitude = 4.20615555555556, - .elevation = 586, - }, - { - .code = "LFOL", - .name = "L'aigle Saint Michel", - .latitude = 48.7588888888889, - .longitude = 0.657777777777778, - .elevation = 787, - }, - { - .code = "LFOM", - .name = "Lessay", - .latitude = 49.2033333333333, - .longitude = -1.50472222222222, - .elevation = 96, - }, - { - .code = "LFON", - .name = "Dreux Vernouillet", - .latitude = 48.7058333333333, - .longitude = 1.36138888888889, - .elevation = 445, - }, - { - .code = "LFOO", - .name = "Les Sables D'olonne Talmont", - .latitude = 46.4755555555556, - .longitude = -1.725, - .elevation = 104, - }, - { - .code = "LFOP", - .name = "Rouen Vallee De Seine", - .latitude = 49.3909527777778, - .longitude = 1.18393611111111, - .elevation = 512, - }, - { - .code = "LFOQ", - .name = "Blois Le Breuil", - .latitude = 47.6798333333333, - .longitude = 1.205775, - .elevation = 398, - }, - { - .code = "LFOR", - .name = "Chartres Metropole", - .latitude = 48.4588888888889, - .longitude = 1.52388888888889, - .elevation = 509, - }, - { - .code = "LFOS", - .name = "Saint Valery Vittefleur", - .latitude = 49.8352777777778, - .longitude = 0.655555555555556, - .elevation = 269, - }, - { - .code = "LFOT", - .name = "Tours Val De Loire", - .latitude = 47.4319444444444, - .longitude = 0.723055555555556, - .elevation = 357, - }, - { - .code = "LFOU", - .name = "Cholet Le Pontreau", - .latitude = 47.0819055555556, - .longitude = -0.877216666666667, - .elevation = 443, - }, - { - .code = "LFOV", - .name = "Laval Entrammes", - .latitude = 48.03225, - .longitude = -0.742780555555556, - .elevation = 330, - }, - { - .code = "LFOW", - .name = "Saint Quentin Roupy", - .latitude = 49.8169444444444, - .longitude = 3.20666666666667, - .elevation = 325, - }, - { - .code = "LFOX", - .name = "Etampes Mondesir", - .latitude = 48.3811111111111, - .longitude = 2.07388888888889, - .elevation = 494, - }, - { - .code = "LFOY", - .name = "Le Havre Saint Romain", - .latitude = 49.5438888888889, - .longitude = 0.359722222222222, - .elevation = 423, - }, - { - .code = "LFOZ", - .name = "Orleans Saint Denis De L'hotel", - .latitude = 47.8976166666667, - .longitude = 2.16420833333333, - .elevation = 397, - }, - { - .code = "LFPA", - .name = "Persan Beaumont", - .latitude = 49.165, - .longitude = 2.31166666666667, - .elevation = 149, - }, - { - .code = "LFPB", - .name = "Paris Le Bourget", - .latitude = 48.969525, - .longitude = 2.44149166666667, - .elevation = 220, - }, - { - .code = "LFPD", - .name = "Bernay Saint Martin", - .latitude = 49.1025, - .longitude = 0.565555555555556, - .elevation = 555, - }, - { - .code = "LFPE", - .name = "Meaux Esbly", - .latitude = 48.9269444444444, - .longitude = 2.83388888888889, - .elevation = 220, - }, - { - .code = "LFPF", - .name = "Beynes Thiverval", - .latitude = 48.8436111111111, - .longitude = 1.90888888888889, - .elevation = 371, - }, - { - .code = "LFPG", - .name = "Paris Charles De Gaulle", - .latitude = 49.0097472222222, - .longitude = 2.54781944444444, - .elevation = 392, - }, - { - .code = "LFPH", - .name = "Chelles Le Pin", - .latitude = 48.8966666666667, - .longitude = 2.60611111111111, - .elevation = 208, - }, - { - .code = "LFPK", - .name = "Coulommiers Voisins", - .latitude = 48.8375, - .longitude = 3.01444444444444, - .elevation = 470, - }, - { - .code = "LFPL", - .name = "Lognes Emerainville", - .latitude = 48.8219444444444, - .longitude = 2.62277777777778, - .elevation = 359, - }, - { - .code = "LFPM", - .name = "Melun Villaroche", - .latitude = 48.6052833333333, - .longitude = 2.67078055555556, - .elevation = 304, - }, - { - .code = "LFPN", - .name = "Toussus Le Noble", - .latitude = 48.7497555555556, - .longitude = 2.11117777777778, - .elevation = 538, - }, - { - .code = "LFPO", - .name = "Paris Orly", - .latitude = 48.7232805555556, - .longitude = 2.37957777777778, - .elevation = 291, - }, - { - .code = "LFPP", - .name = "Le Plessis Belleville", - .latitude = 49.1091666666667, - .longitude = 2.73694444444444, - .elevation = 387, - }, - { - .code = "LFPQ", - .name = "Fontenay Tresigny", - .latitude = 48.7061111111111, - .longitude = 2.90277777777778, - .elevation = 371, - }, - { - .code = "LFPT", - .name = "Pontoise Cormeilles En Vexin", - .latitude = 49.0966277777778, - .longitude = 2.04072222222222, - .elevation = 325, - }, - { - .code = "LFPU", - .name = "Moret Episy", - .latitude = 48.3408333333333, - .longitude = 2.79777777777778, - .elevation = 253, - }, - { - .code = "LFPV", - .name = "Villacoublay Velizy", - .latitude = 48.7741722222222, - .longitude = 2.19138888888889, - .elevation = 585, - }, - { - .code = "LFPX", - .name = "Chavenay Villepreux", - .latitude = 48.8422222222222, - .longitude = 1.98027777777778, - .elevation = 424, - }, - { - .code = "LFPZ", - .name = "Saint Cyr L'ecole", - .latitude = 48.8102777777778, - .longitude = 2.07333333333333, - .elevation = 373, - }, - { - .code = "LFQA", - .name = "Reims Prunay", - .latitude = 49.2086888888889, - .longitude = 4.15658055555556, - .elevation = 313, - }, - { - .code = "LFQB", - .name = "Troyes Barberey", - .latitude = 48.3216194444445, - .longitude = 4.01662222222222, - .elevation = 389, - }, - { - .code = "LFQC", - .name = "Luneville Croismare", - .latitude = 48.5936111111111, - .longitude = 6.54222222222222, - .elevation = 790, - }, - { - .code = "LFQD", - .name = "Arras Roclincourt", - .latitude = 50.3238888888889, - .longitude = 2.80277777777778, - .elevation = 337, - }, - { - .code = "LFQE", - .name = "Etain Rouvres", - .latitude = 49.2290888888889, - .longitude = 5.67603888888889, - .elevation = 760, - }, - { - .code = "LFQF", - .name = "Autun Bellevue", - .latitude = 46.9711111111111, - .longitude = 4.26111111111111, - .elevation = 1001, - }, - { - .code = "LFQG", - .name = "Nevers Fourchambault", - .latitude = 47.0037305555556, - .longitude = 3.11074166666667, - .elevation = 602, - }, - { - .code = "LFQH", - .name = "Chatillon Sur Seine", - .latitude = 47.8452777777778, - .longitude = 4.57944444444444, - .elevation = 906, - }, - { - .code = "LFQJ", - .name = "Maubeuge Elesmes", - .latitude = 50.3083333333333, - .longitude = 4.03, - .elevation = 452, - }, - { - .code = "LFQK", - .name = "Chalons Ecury Sur Coole", - .latitude = 48.9055555555556, - .longitude = 4.35277777777778, - .elevation = 321, - }, - { - .code = "LFQL", - .name = "Lens Benifontaine", - .latitude = 50.4663888888889, - .longitude = 2.81972222222222, - .elevation = 170, - }, - { - .code = "LFQM", - .name = "Besancon La Veze", - .latitude = 47.2053083333333, - .longitude = 6.08055, - .elevation = 1270, - }, - { - .code = "LFQN", - .name = "Saint Omer Wizernes", - .latitude = 50.7288888888889, - .longitude = 2.23444444444444, - .elevation = 249, - }, - { - .code = "LFQO", - .name = "Lille Marcq En Baroeul", - .latitude = 50.6872222222222, - .longitude = 3.07555555555556, - .elevation = 70, - }, - { - .code = "LFQP", - .name = "Phalsbourg Bourscheid", - .latitude = 48.7681527777778, - .longitude = 7.20513055555556, - .elevation = 1018, - }, - { - .code = "LFQQ", - .name = "Lille Lesquin", - .latitude = 50.563425, - .longitude = 3.08682222222222, - .elevation = 157, - }, - { - .code = "LFQS", - .name = "Vitry En Artois", - .latitude = 50.3375, - .longitude = 2.99194444444444, - .elevation = 174, - }, - { - .code = "LFQT", - .name = "Merville Calonne", - .latitude = 50.6166, - .longitude = 2.64009444444444, - .elevation = 61, - }, - { - .code = "LFQU", - .name = "Sarre Union", - .latitude = 48.9508333333333, - .longitude = 7.07638888888889, - .elevation = 842, - }, - { - .code = "LFQV", - .name = "Charleville Mezieres", - .latitude = 49.7850527777778, - .longitude = 4.64280833333333, - .elevation = 492, - }, - { - .code = "LFQW", - .name = "Vesoul Frotey", - .latitude = 47.6386111111111, - .longitude = 6.20416666666667, - .elevation = 1249, - }, - { - .code = "LFQX", - .name = "Juvancourt", - .latitude = 48.1138888888889, - .longitude = 4.81944444444444, - .elevation = 1147, - }, - { - .code = "LFQY", - .name = "Saverne Steinbourg", - .latitude = 48.7533333333333, - .longitude = 7.42583333333333, - .elevation = 623, - }, - { - .code = "LFQZ", - .name = "Dieuze Gueblange", - .latitude = 48.7744444444444, - .longitude = 6.71416666666667, - .elevation = 718, - }, - { - .code = "LFRB", - .name = "Brest Bretagne", - .latitude = 48.4471305555556, - .longitude = -4.42175277777778, - .elevation = 325, - }, - { - .code = "LFRC", - .name = "Cherbourg Maupertus", - .latitude = 49.650775, - .longitude = -1.4753, - .elevation = 459, - }, - { - .code = "LFRD", - .name = "Dinard Pleurtuit Saint Malo", - .latitude = 48.5877055555556, - .longitude = -2.07995, - .elevation = 219, - }, - { - .code = "LFRE", - .name = "La Baule Escoublac", - .latitude = 47.2883333333333, - .longitude = -2.34694444444444, - .elevation = 106, - }, - { - .code = "LFRF", - .name = "Granville-Mont Saint Michel", - .latitude = 48.882875, - .longitude = -1.56383333333333, - .elevation = 45, - }, - { - .code = "LFRG", - .name = "Deauville Normandie", - .latitude = 49.3633944444444, - .longitude = 0.159997222222222, - .elevation = 479, - }, - { - .code = "LFRH", - .name = "Lorient Lann Bihoue", - .latitude = 47.7605555555556, - .longitude = -3.44, - .elevation = 159, - }, - { - .code = "LFRI", - .name = "La Roche Sur Yon Les Ajoncs", - .latitude = 46.7023833333333, - .longitude = -1.38175833333333, - .elevation = 299, - }, - { - .code = "LFRJ", - .name = "Landivisiau", - .latitude = 48.5302583333333, - .longitude = -4.15164166666667, - .elevation = 348, - }, - { - .code = "LFRK", - .name = "Caen Carpiquet", - .latitude = 49.1732805555556, - .longitude = -0.449875, - .elevation = 256, - }, - { - .code = "LFRL", - .name = "Lanveoc Poulmic", - .latitude = 48.2825305555556, - .longitude = -4.44369166666667, - .elevation = 287, - }, - { - .code = "LFRM", - .name = "Le Mans Arnage", - .latitude = 47.9484916666667, - .longitude = 0.201647222222222, - .elevation = 194, - }, - { - .code = "LFRN", - .name = "Rennes Saint Jacques", - .latitude = 48.0719333333333, - .longitude = -1.73223333333333, - .elevation = 124, - }, - { - .code = "LFRO", - .name = "Lannion", - .latitude = 48.7544444444444, - .longitude = -3.47194444444444, - .elevation = 290, - }, - { - .code = "LFRP", - .name = "Ploermel Loyat", - .latitude = 48.0018555555556, - .longitude = -2.37871944444444, - .elevation = 237, - }, - { - .code = "LFRQ", - .name = "Quimper Pluguffan", - .latitude = 47.9749472222222, - .longitude = -4.167875, - .elevation = 293, - }, - { - .code = "LFRS", - .name = "Nantes Atlantique", - .latitude = 47.1570194444444, - .longitude = -1.60780833333333, - .elevation = 90, - }, - { - .code = "LFRT", - .name = "Saint Brieuc Armor", - .latitude = 48.5374916666667, - .longitude = -2.85654166666667, - .elevation = 452, - }, - { - .code = "LFRU", - .name = "Morlaix Ploujean", - .latitude = 48.6007472222222, - .longitude = -3.81666944444444, - .elevation = 277, - }, - { - .code = "LFRV", - .name = "Vannes Meucon", - .latitude = 47.7192444444444, - .longitude = -2.72337777777778, - .elevation = 440, - }, - { - .code = "LFRW", - .name = "Avranches Le Val Saint Pere", - .latitude = 48.6608333333333, - .longitude = -1.40583333333333, - .elevation = 25, - }, - { - .code = "LFRZ", - .name = "Saint Nazaire Montoir", - .latitude = 47.31065, - .longitude = -2.15680277777778, - .elevation = 13, - }, - { - .code = "LFSA", - .name = "Besancon Thise", - .latitude = 47.2736111111111, - .longitude = 6.08305555555556, - .elevation = 807, - }, - { - .code = "LFSB", - .name = "Bale-Mulhouse", - .latitude = 47.5898777777778, - .longitude = 7.52922222222222, - .elevation = 885, - }, - { - .code = "LFSD", - .name = "Dijon-Longvic", - .latitude = 47.2658166666667, - .longitude = 5.09497777777778, - .elevation = 728, - }, - { - .code = "LFSE", - .name = "Epinal Dogneville", - .latitude = 48.2113888888889, - .longitude = 6.44833333333333, - .elevation = 1041, - }, - { - .code = "LFSF", - .name = "Metz Frescaty", - .latitude = 49.0763888888889, - .longitude = 6.13388888888889, - .elevation = 629, - }, - { - .code = "LFSG", - .name = "Epinal Mirecourt", - .latitude = 48.3250055555556, - .longitude = 6.06674166666667, - .elevation = 1084, - }, - { - .code = "LFSH", - .name = "Haguenau", - .latitude = 48.7969444444444, - .longitude = 7.81916666666667, - .elevation = 491, - }, - { - .code = "LFSI", - .name = "Saint Dizier Robinson", - .latitude = 48.6335361111111, - .longitude = 4.90818888888889, - .elevation = 459, - }, - { - .code = "LFSJ", - .name = "Sedan Douzy", - .latitude = 49.6588888888889, - .longitude = 5.03666666666667, - .elevation = 513, - }, - { - .code = "LFSK", - .name = "Vitry Le Francois Vauclerc", - .latitude = 48.7022222222222, - .longitude = 4.68333333333333, - .elevation = 411, - }, - { - .code = "LFSL", - .name = "Brive Souillac", - .latitude = 45.0396388888889, - .longitude = 1.48566666666667, - .elevation = 1016, - }, - { - .code = "LFSM", - .name = "Montbeliard Courcelles", - .latitude = 47.4866611111111, - .longitude = 6.79146944444444, - .elevation = 1041, - }, - { - .code = "LFSN", - .name = "Nancy Essey", - .latitude = 48.6920861111111, - .longitude = 6.22605, - .elevation = 757, - }, - { - .code = "LFSO", - .name = "Nancy Ochey", - .latitude = 48.5831861111111, - .longitude = 5.954525, - .elevation = 1106, - }, - { - .code = "LFSP", - .name = "Pontarlier", - .latitude = 46.9083333333333, - .longitude = 6.32916666666667, - .elevation = 2683, - }, - { - .code = "LFSS", - .name = "Saint Sulpice Des Landes", - .latitude = 47.7916666666667, - .longitude = -1.64361111111111, - .elevation = 312, - }, - { - .code = "LFST", - .name = "Strasbourg Entzheim", - .latitude = 48.5419444444444, - .longitude = 7.63444444444444, - .elevation = 505, - }, - { - .code = "LFSU", - .name = "Langres Rolampont", - .latitude = 47.9641666666667, - .longitude = 5.29361111111111, - .elevation = 1375, - }, - { - .code = "LFSV", - .name = "Pont Saint Vincent", - .latitude = 48.6, - .longitude = 6.05638888888889, - .elevation = 1339, - }, - { - .code = "LFSW", - .name = "Epernay Plivot", - .latitude = 49.0044444444444, - .longitude = 4.08527777777778, - .elevation = 291, - }, - { - .code = "LFSX", - .name = "Luxeuil Saint Sauveur", - .latitude = 47.7872222222222, - .longitude = 6.365, - .elevation = 886, - }, - { - .code = "LFSY", - .name = "Cessey Baigneux Les Juifs", - .latitude = 47.6097222222222, - .longitude = 4.6175, - .elevation = 1175, - }, - { - .code = "LFTB", - .name = "Marignane Berre", - .latitude = 43.45, - .longitude = 5.21666666666667, - .elevation = 0, - }, - { - .code = "LFTF", - .name = "Cuers Pierrefeu", - .latitude = 43.2475888888889, - .longitude = 6.12729444444444, - .elevation = 269, - }, - { - .code = "LFTH", - .name = "Hyeres Le Palyvestre", - .latitude = 43.0973444444444, - .longitude = 6.14603055555556, - .elevation = 13, - }, - { - .code = "LFTM", - .name = "Serres La Batie Montsaleon", - .latitude = 44.4572222222222, - .longitude = 5.72722222222222, - .elevation = 2328, - }, - { - .code = "LFTN", - .name = "La Grand'combe", - .latitude = 44.2430555555556, - .longitude = 4.01111111111111, - .elevation = 1623, - }, - { - .code = "LFTP", - .name = "Puimoisson", - .latitude = 43.8688888888889, - .longitude = 6.16277777777778, - .elevation = 2469, - }, - { - .code = "LFTQ", - .name = "Chateaubriant Pouance", - .latitude = 47.7405555555556, - .longitude = -1.18805555555556, - .elevation = 322, - }, - { - .code = "LFTW", - .name = "Nimes Garons", - .latitude = 43.7574277777778, - .longitude = 4.41634444444444, - .elevation = 309, - }, - { - .code = "LFTZ", - .name = "La Mole", - .latitude = 43.2052777777778, - .longitude = 6.48194444444444, - .elevation = 59, - }, - { - .code = "LFXA", - .name = "Amberieu", - .latitude = 45.9797222222222, - .longitude = 5.33777777777778, - .elevation = 823, - }, - { - .code = "LFXB", - .name = "Saintes Thenac", - .latitude = 45.7019444444445, - .longitude = -0.636111111111111, - .elevation = 118, - }, - { - .code = "LFXG", - .name = "Bitche", - .latitude = 49.0666666666667, - .longitude = 7.45, - .elevation = 985, - }, - { - .code = "LFXH", - .name = "Le Valdahon", - .latitude = 47.1666666666667, - .longitude = 6.35, - .elevation = 2067, - }, - { - .code = "LFXQ", - .name = "Coetquidan", - .latitude = 47.9438888888889, - .longitude = -2.18194444444444, - .elevation = 499, - }, - { - .code = "LFXU", - .name = "Les Mureaux", - .latitude = 48.9986111111111, - .longitude = 1.94166666666667, - .elevation = 91, - }, - { - .code = "LFYG", - .name = "Cambrai Niergnies", - .latitude = 50.1425, - .longitude = 3.265, - .elevation = 312, - }, - { - .code = "LFYR", - .name = "Romorantin Pruniers", - .latitude = 47.3208333333333, - .longitude = 1.68888888888889, - .elevation = 289, - }, - { - .code = "LFYS", - .name = "Sainte Leocadie", - .latitude = 42.4472222222222, - .longitude = 2.01083333333333, - .elevation = 4331, - }, - { - .code = "LFYV", - .name = "Yvetot-Baons Le Comte", - .latitude = 49.6386111111111, - .longitude = 0.7325, - .elevation = 463, - } -}; -static size_t nfrench_airports = sizeof(french_airports) / sizeof(french_airports[0]); -#endif /* AIRPORT_H */ diff --git a/dialogs/airports-list-model.c b/dialogs/airports-list-model.c deleted file mode 100644 index 2cc695c..0000000 --- a/dialogs/airports-list-model.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#define _GNU_SOURCE -#include -#include -#include - -#include "misc.h" -#include "list-box.h" -#include "airports-list-model.h" -#include "dialogs/airport.h" - -static AirportListModel *airport_list_model_dispose(AirportListModel *self); -static ListModelOps airport_list_model_ops = { - .dispose = (DisposeFunc)airport_list_model_dispose -}; - -AirportListModel *airport_list_model_new() -{ - AirportListModel *self; - - self = calloc(1, sizeof(AirportListModel)); - if(self){ - if(!airport_list_model_init(self)) - return (AirportListModel*)list_model_free(LIST_MODEL(self)); - } - return self; -} - -AirportListModel *airport_list_model_init(AirportListModel *self) -{ - if(!list_model_init(LIST_MODEL(self), &airport_list_model_ops, nfrench_airports)) - return NULL; - - self->nfullnames = nfrench_airports; - self->fullnames = malloc(sizeof(char *) * self->nfullnames); - if(!self->fullnames) - return NULL; -#if 1 - size_t binsize = 0; - for(int i = 0; i < nfrench_airports; i++){ - binsize += strlen(french_airports[i].code); - binsize += 3; /* strlen(" - ") */ - binsize += strlen(french_airports[i].name); - binsize += 1; /*final \0 byte */ - } - - self->namestash = malloc(sizeof(char)*binsize); - if(!self->namestash) - return NULL; - - char *stashptr = self->namestash; - for(int i = 0; i < nfrench_airports; i++){ - self->fullnames[i] = stashptr; - strcpy(stashptr, french_airports[i].code); - strcat(stashptr, " - "); - strcat(stashptr, french_airports[i].name); - while(*stashptr != '\0') stashptr++; - stashptr++; - } -#else - for(int i = 0; i < nfrench_airports; i++){ - asprintf(&self->fullnames[i], - "%s - %s", - french_airports[i].code, - french_airports[i].name - ); - } -#endif - LIST_MODEL(self)->maxlen = 0; - for(int i = 0; i < self->nfullnames; i++){ - LIST_MODEL(self)->rows[i].key = &french_airports[i]; - LIST_MODEL(self)->rows[i].label = self->fullnames[i]; - LIST_MODEL(self)->row_lenghts[i] = strlen(self->fullnames[i]); - LIST_MODEL(self)->maxlen = MAX( - LIST_MODEL(self)->maxlen, - LIST_MODEL(self)->row_lenghts[i] - ); - } - LIST_MODEL(self)->nrows = self->nfullnames; - - return self; -} - -static AirportListModel *airport_list_model_dispose(AirportListModel *self) -{ - list_model_dispose(LIST_MODEL(self)); - if(self->fullnames){ -#if 0 - for(int i = 0; i < nfrench_airports; i++){ - if(self->fullnames[i]) - free(self->fullnames[i]); - } -#endif - free(self->fullnames); - } - if(self->namestash) - free(self->namestash); - return self; -} - -void airport_list_model_filter(AirportListModel *self, const char *filter) -{ - ListModel *lself = LIST_MODEL(self); - - lself->nrows = 0; - for(int i = 0; i < self->nfullnames; i++){ - if(!filter || strcasestr(self->fullnames[i], filter)){ - lself->rows[lself->nrows].key = &french_airports[i]; - lself->rows[lself->nrows].label = self->fullnames[i]; - lself->row_lenghts[lself->nrows] = strlen(self->fullnames[i]); - lself->nrows++; - } - } - list_box_model_changed(lself->listbox); -} - diff --git a/dialogs/airports-list-model.h b/dialogs/airports-list-model.h deleted file mode 100644 index 8e3fd1c..0000000 --- a/dialogs/airports-list-model.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef AIRPORTS_LIST_MODEL_H -#define AIRPORTS_LIST_MODEL_H -#include "list-model.h" -#include "airport.h" - -typedef struct{ - ListModel super; - - char *namestash; - - char **fullnames; - size_t nfullnames; -}AirportListModel; - - -AirportListModel *airport_list_model_new(); -AirportListModel *airport_list_model_init(AirportListModel *self); - -void airport_list_model_filter(AirportListModel *self, const char *filter); -#endif /* AIRPORTS_LIST_MODEL_H */ diff --git a/dialogs/direct-to-dialog.c b/dialogs/direct-to-dialog.c deleted file mode 100644 index 35b9b9d..0000000 --- a/dialogs/direct-to-dialog.c +++ /dev/null @@ -1,332 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#define _GNU_SOURCE -#include -#include -#include - -#include "direct-to-dialog.h" - -#include "base-gauge.h" -#include "base-widget.h" -#include "sdl-colors.h" -#include "dialogs/airports-list-model.h" -#include "text-box.h" -#include "text-gauge.h" -#include "misc.h" -#include "data-source.h" - -static void direct_to_dialog_render(DirectToDialog *self, Uint32 dt, RenderContext *ctx); -static bool direct_to_dialog_handle_event(DirectToDialog *self, SDL_KeyboardEvent *event); -static void update_list_content(TextBox *txtbx, DirectToDialog *self); -static void selection_changed(DirectToDialog *self, ListBox *sender); -static void button_pressed(DirectToDialog *self, Button *sender); - -static BaseWidgetOps direct_to_dialog_ops = { - .super.render = (RenderFunc)direct_to_dialog_render, - .super.update_state = (StateUpdateFunc)NULL, - .super.dispose = (DisposeFunc)NULL, - .handle_event = (EventHandlerFunc)direct_to_dialog_handle_event -}; - - -DirectToDialog *direct_to_dialog_new() -{ - DirectToDialog *self; - self = calloc(1, sizeof(DirectToDialog)); - if(self){ - if(!direct_to_dialog_init(self)) - return base_gauge_free(BASE_GAUGE(self)); - - } - return self; -} - -DirectToDialog *direct_to_dialog_init(DirectToDialog *self) -{ - base_widget_init(BASE_WIDGET(self), - &direct_to_dialog_ops, - 12*20, 304 - ); - - PCF_Font *fnt = resource_manager_get_font(TERMINUS_24); - self->text = text_box_new( - TERMINUS_24, - 12*20, - PCF_FontCharHeight(fnt) - ); - text_box_set_allowed_chars(self->text, true, 3, " -", PCF_UPPER_CASE, PCF_DIGITS); - self->text->changed_callback = (TextBoxTextChanged)update_list_content; - self->text->userdata = self; - - self->list = list_box_new( - TERMINUS_24, - BASE_GAUGE(self->text)->frame.w, - 200 - ); - - list_box_set_selection_changed_listener(self->list, - (EventListenerFunc)selection_changed, - self - ); - - self->focused = BASE_WIDGET(self->text); - self->focused->has_focus = true; - - self->bearing_lbl = text_gauge_new("BRG", true, 35, 24); - text_gauge_set_static_font(self->bearing_lbl, - resource_manager_get_static_font(TERMINUS_24, - &SDL_WHITE, - 1, PCF_ALPHA - ) - ); - self->bearing_lbl->alignment = VALIGN_MIDDLE | HALIGN_LEFT; - self->bearing_value = text_gauge_new(NULL, true, 52, 24); - text_gauge_set_size(self->bearing_lbl, 4); - self->bearing_value->alignment = VALIGN_MIDDLE | HALIGN_LEFT; - text_gauge_set_static_font(self->bearing_value, - resource_manager_get_static_font(TERMINUS_24, - &SDL_CYAN, - 1, PCF_DIGITS - ) - ); - - - self->distance_lbl = text_gauge_new("DIS", true, 35, 24); - text_gauge_set_static_font(self->distance_lbl, - resource_manager_get_static_font(TERMINUS_24, - &SDL_WHITE, - 1, PCF_ALPHA - ) - ); - self->distance_lbl->alignment = VALIGN_MIDDLE | HALIGN_LEFT; - self->distance_value = text_gauge_new(NULL, true, 60, 24); - text_gauge_set_size(self->distance_value, 4); - self->distance_value->alignment = VALIGN_MIDDLE | HALIGN_LEFT; - text_gauge_set_static_font(self->distance_value, - resource_manager_get_static_font(TERMINUS_24, - &SDL_CYAN, - 1, PCF_DIGITS - ) - ); - - - self->latitude = text_gauge_new(NULL, true, 135, 24); - text_gauge_set_size(self->latitude, 14); - self->latitude->alignment = VALIGN_MIDDLE | HALIGN_RIGHT; - text_gauge_set_static_font(self->latitude, - resource_manager_get_static_font(TERMINUS_24, - &SDL_CYAN, - 2, PCF_DIGITS, - "NSEW" - ) - ); - - self->longitude = text_gauge_new(NULL, true, 135, 24); - text_gauge_set_size(self->longitude, 14); - self->longitude->alignment = VALIGN_MIDDLE | HALIGN_RIGHT; - text_gauge_set_static_font(self->longitude, - resource_manager_get_static_font(TERMINUS_24, - &SDL_CYAN, - 2, PCF_DIGITS, - "NSEW" - ) - ); - - self->validate_button = button_new( - "Validate", TERMINUS_24, - SDL_WHITE, SDL_BLACK, - BASE_GAUGE(self)->frame.w, 24 - ); - self->validate_button->validated = (EventListener){ - .callback = (EventListenerFunc)button_pressed, - .target = self - }; - - base_gauge_add_child(BASE_GAUGE(self), BASE_GAUGE(self->text), 0, 0); - base_gauge_add_child(BASE_GAUGE(self), - BASE_GAUGE(self->list), - 0, - BASE_GAUGE(self->text)->frame.h + 3 - ); - - /*lat/lon*/ - base_gauge_add_child(BASE_GAUGE(self), - BASE_GAUGE(self->latitude), - SDLExt_RectLastX(&BASE_GAUGE(self)->frame) - BASE_GAUGE(self->latitude)->frame.w + 1, - SDLExt_RectLastY(&BASE_GAUGE(self->list)->frame) + 3 - ); - base_gauge_add_child(BASE_GAUGE(self), - BASE_GAUGE(self->longitude), - SDLExt_RectLastX(&BASE_GAUGE(self)->frame) - BASE_GAUGE(self->longitude)->frame.w + 1, - SDLExt_RectLastY(&BASE_GAUGE(self->latitude)->frame) + 3 - ); - - /*Bearing*/ - base_gauge_add_child(BASE_GAUGE(self), - BASE_GAUGE(self->bearing_lbl), - 0, - SDLExt_RectLastY(&BASE_GAUGE(self->latitude)->frame) - - (BASE_GAUGE(self->bearing_lbl)->frame.h-1) - ); - base_gauge_add_child(BASE_GAUGE(self), - BASE_GAUGE(self->bearing_value), - SDLExt_RectLastX(&BASE_GAUGE(self->bearing_lbl)->frame)+1, - BASE_GAUGE(self->latitude)->frame.y - ); - - /*Distance*/ - base_gauge_add_child(BASE_GAUGE(self), - BASE_GAUGE(self->distance_lbl), - 0, - SDLExt_RectLastY(&BASE_GAUGE(self->longitude)->frame) - - (BASE_GAUGE(self->distance_lbl)->frame.h-1) - ); - base_gauge_add_child(BASE_GAUGE(self), - BASE_GAUGE(self->distance_value), - SDLExt_RectLastX(&BASE_GAUGE(self->distance_lbl)->frame)+1, - BASE_GAUGE(self->longitude)->frame.y - ); - - base_gauge_add_child(BASE_GAUGE(self), - BASE_GAUGE(self->validate_button), - 0, - SDLExt_RectLastY(&BASE_GAUGE(self->distance_lbl)->frame)+2 - ); - - list_box_set_model(self->list, LIST_MODEL(airport_list_model_new())); - - self->visible = true; - return self; -} - -void direct_to_dialog_reset(DirectToDialog *self) -{ - text_box_set_text(self->text, NULL); - airport_list_model_filter((AirportListModel*)self->list->model, NULL); - self->focused->has_focus = false; - self->focused = BASE_WIDGET(self->text); - self->focused->has_focus = true; -} - -static void direct_to_dialog_render(DirectToDialog *self, Uint32 dt, RenderContext *ctx) -{ - base_gauge_fill(BASE_GAUGE(self), ctx, NULL, &SDL_BLACK, false); -} - -static bool direct_to_dialog_handle_event(DirectToDialog *self, SDL_KeyboardEvent *event) -{ - /*TODO: Have a Dialog superclass that cycles through children? - * Problem: we'll need some type of RTTI + ancestry or have a second - * set of children referencing only BaseWidget derivatives - * */ - bool keep_focus = base_widget_handle_event(self->focused, event); - if(!keep_focus){ - self->focused->has_focus = false; - - if(self->focused == BASE_WIDGET(self->text)) - self->focused = BASE_WIDGET(self->list); - else if(self->focused == BASE_WIDGET(self->list)) - self->focused = BASE_WIDGET(self->validate_button); - else if(self->focused == BASE_WIDGET(self->validate_button)) - self->focused = BASE_WIDGET(self->text); - - - self->focused->has_focus = true; - } - return true; -} - -static void update_list_content(TextBox *txtbx, DirectToDialog *self) -{ - airport_list_model_filter((AirportListModel*)self->list->model, txtbx->text); -} - -static void clear_values(DirectToDialog *self) -{ - text_gauge_set_value(self->latitude, ""); - text_gauge_set_value(self->longitude, ""); - text_gauge_set_value(self->bearing_value, ""); - text_gauge_set_value(self->distance_value, ""); -} - -static void selection_changed(DirectToDialog *self, ListBox *sender) -{ - DataSource *ds; - GeoLocation me, ap; - - ListModelRow *row = list_box_get_selected(sender); - if(!row){ - return clear_values(self); - } - Airport *airport = (Airport*)row->key; - - geo_location_latitude_to_dms(airport->latitude, self->latitude->value); - self->latitude->len = strlen(self->latitude->value); -// printf("self->latitude->value: %s\n",self->latitude->value); - BASE_GAUGE(self->latitude)->dirty = true; - - geo_location_longitude_to_dms(airport->longitude, self->longitude->value); - self->longitude->len = strlen(self->longitude->value); - BASE_GAUGE(self->longitude)->dirty = true; - - ds = data_source_get_instance(); - if(!ds) return; - - me = *(GeoLocation*)&ds->location; - ap = (GeoLocation){airport->latitude, airport->longitude}; - - double distance = geo_location_distance_to(&me, &ap); - distance /= 1852; /*convert to NM*/ - /* 4-digits are enough to represent the longest NM distance - * between two points on earth */ - text_gauge_set_value_formatn(self->distance_value, 4, "%d", (int)round(distance)); - - double bearing = geo_location_bearing(&me, &ap); - text_gauge_set_value_formatn(self->bearing_value, 4, "%d\x8f", (int)round(bearing)); - -#if 0 - printf("Current selection: code: %s name: %s latitude: %f " - "longitude: %f elevation: %d\n", - airport->code, - airport->name, - airport->latitude, - airport->longitude, - airport->elevation - ); -#endif -} - - -static void button_pressed(DirectToDialog *self, Button *sender) -{ - ListModelRow *row = list_box_get_selected(self->list); - if(!row){ - return clear_values(self); - } - Airport *airport = (Airport*)row->key; - - DataSource *ds = data_source_get_instance(); - if(!ds) return; - - printf("Current selection: code: %s name: %s latitude: %f " - "longitude: %f elevation: %d\n", - airport->code, - airport->name, - airport->latitude, - airport->longitude, - airport->elevation - ); - - data_source_set_route_data(ds, &(RouteData){ - .from = ds->location.super, - .to = (GeoLocation){airport->latitude, airport->longitude} - }); - - self->visible = false; -} diff --git a/dialogs/direct-to-dialog.h b/dialogs/direct-to-dialog.h deleted file mode 100644 index 59126f7..0000000 --- a/dialogs/direct-to-dialog.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef DIRECT_TO_H -#define DIRECT_TO_H -#include "base-widget.h" -#include "button.h" -#include "list-box.h" -#include "text-box.h" -#include "text-gauge.h" - -typedef struct{ - BaseWidget super; - bool visible; - - TextBox *text; - ListBox *list; - - TextGauge *bearing_lbl; - TextGauge *distance_lbl; - - TextGauge *bearing_value; - TextGauge *distance_value; - - - TextGauge *latitude; - TextGauge *longitude; - - Button *validate_button; - - BaseWidget *focused; -}DirectToDialog; - - -DirectToDialog *direct_to_dialog_new(); -DirectToDialog *direct_to_dialog_init(DirectToDialog *self); -void direct_to_dialog_reset(DirectToDialog *self); -#endif /* DIRECT_TO_H */ diff --git a/digit-barrel.c b/digit-barrel.c deleted file mode 100644 index 7db0ba6..0000000 --- a/digit-barrel.c +++ /dev/null @@ -1,235 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#define _GNU_SOURCE -#include -#include -#include - -#include "digit-barrel.h" -#include "sdl-colors.h" -#include "misc.h" - - -DigitBarrel *digit_barrel_new(PCF_Font *font, float start, float end, float step) -{ - DigitBarrel *self; - - self = calloc(1, sizeof(DigitBarrel)); - if(self){ - if(!digit_barrel_init(self, font, start, end, step)){ - free(self); - return NULL; - } - } -// printf("DigitBarrel %p new\n",self); - return self; -} - -/** - * Creates an odometer-like gauge from @param start to @param end - * - * @param font_size: Font size to use in pixels - * @param start: first value (i.e 0, 10, etc.) - * @param end: last "full" value. Should be 9.999, 99, etc. To account for rotation - * @param step: increment between two values (1,15, etc.) - */ -DigitBarrel *digit_barrel_init(DigitBarrel *self, PCF_Font *font, float start, float end, float step) -{ - Uint32 advance, font_height; - int vheight, vwidth; - int ndigits; - float maxvalue; - float minv, maxv; - SDL_Surface *tmp; - char *number; - SDL_Rect cursor; /*write cursor (into VERTICAL_SPLIT(self)->ruler)*/ - SDL_Rect fcursor; /*font read cursor*/ - char fmt[10]; - VerticalStrip *strip; - GenericLayer *layer; - - strip = VERTICAL_STRIP(self); - layer = GENERIC_LAYER(self); - - strip->start = start; - strip->end = end; - - maxvalue = fabs((end > start) ? end : start); - maxvalue = (maxvalue > 0) ? maxvalue : 1; - ndigits = floor(log10f(maxvalue) + 1); - - number = alloca(sizeof(char)*(ndigits+1)); /*There shouldn't be that much digits*/ - snprintf(fmt, 10, "%%0%dd", ndigits); - - PCF_FontGetSizeRequest(font, "0", false, &advance, &font_height); - vheight = round((fabs(end-start)) / step)*font_height; /*end should be .9999 so there is no need for the +1*/ - vwidth = advance * ndigits; - - generic_layer_init_with_masks(GENERIC_LAYER(self), vwidth, vheight, 0, 0, 0, 0); - - minv = (start < end) ? start : end; - maxv = (start > end) ? start : end; - cursor = (SDL_Rect){0,0,generic_layer_w(layer), font_height}; - fcursor = (SDL_Rect){0,0,vwidth, font_height}; - Uint32 white = SDL_UWHITE(layer->canvas); - for(float i = minv; i < maxv; i += step){ - snprintf(number, 6, fmt, (int)round(i)); - PCF_FontWrite(font, number, white, false, layer->canvas, &cursor); - cursor.y += cursor.h; - cursor.x = 0; /*PCF_FontWrite advances the cursor*/ - } - - self->symbol_h = font_height; - self->fei = round((self->symbol_h-1)/2.0); - /* The value is the centerline of the digit. - * There is exactly @param step between two digits' - * centerlines. This dimension (between centerlnes) - * happend to be the same as the symbol size,i as it - * is two consective halves of a symbol - * */ - strip->ppv = self->symbol_h / step; - - generic_layer_build_texture(layer); -// digit_barrel_draw_etch_marks(self); - return self; -} - -void digit_barrel_free(DigitBarrel *self) -{ - if(self->refcount > 0) - self->refcount--; - if(!self->refcount){ -// printf("DigitBarrel %p free\n",self); - vertical_strip_dispose(VERTICAL_STRIP(self)); - free(self); - } -} - - - - -/** - * Returns pixel index (i.e y) - * from a given value - * - * @param value the value to look for - * @param reverse if true, assumes that 0 is a the bottom of the strip instead of - * at the top - * @return the pixel index in {@link #ruler} that maps to @param value, or -1 if value - * can't be mapped (outside of the [{@link #start}, {@link #end}] range) - */ -float digit_barrel_resolve_value(DigitBarrel *self, float value) -{ - VerticalStrip *strip; - float y; - - strip = VERTICAL_STRIP(self); - if(!vertical_strip_has_value(strip, value)) - return -1; - - value = fmod(value, fabs(strip->end - strip->start) + 1); - y = value * strip->ppv + self->fei; - - return round(y); -} - -/* - * Rubis is the offset in region where to align the value fomr the spinner. - * if its negative, the rubis will be (vertical) the center dst: the y index - * in the value spinner representing @param value will be aligned with the middle - * - */ -void digit_barrel_state_value(DigitBarrel *self, float value, SDL_Rect *region, float rubis, DigitBarrelState *state) -{ - float y; - SDL_Rect dst_region = {region->x,region->y,region->w,region->h}; - VerticalStrip *strip; - GenericLayer *layer; - - strip = VERTICAL_STRIP(self); - layer = GENERIC_LAYER(self); - - /*translate @param value to an index in the spinner texture*/ - y = digit_barrel_resolve_value(self, value); - rubis = (rubis < 0) ? region->h / 2.0 : rubis; - SDL_Rect portion = { - .x = 0, - .y = round(y - rubis), - .w = generic_layer_w(layer), - .h = region->h - }; - /* Ensures that portion.y + portion.h doesn't got past image bounds: - * w/h are ignored by SDL_BlitSurface, but when using SDL_Renderers wrong - * values will stretch the image. - */ - if(portion.y + portion.h > generic_layer_h(layer)) - portion.h = generic_layer_h(layer) - portion.y; - - state->layer = layer; - if(portion.y < 0){ //Fill top - SDL_Rect patch = { - .x = 0, - .y = generic_layer_h(layer) + portion.y, //means - portion.y as portion.y < 0 here - .w = generic_layer_w(layer), - .h = generic_layer_h(layer) - patch.y - }; - state->patches[state->npatches].src = patch; - state->patches[state->npatches].dst = dst_region; - state->npatches++; - - dst_region.y = patch.h; - portion.y = 0; - portion.h -= patch.h; - } - state->patches[state->npatches].src = portion; - state->patches[state->npatches].dst = dst_region; - state->npatches++; - - if(portion.y + region->h > generic_layer_h(layer)){// fill bottom - float taken = generic_layer_h(layer) - portion.y; //number of pixels taken from the bottom of values pict - float delta = region->h - taken; - dst_region.y += taken; - SDL_Rect patch = { - .x = 0, - .y = 0, - .w = generic_layer_w(layer), - .h = delta - }; - state->patches[state->npatches].src = patch; - state->patches[state->npatches].dst = dst_region; - state->npatches++; - } -} - - -void digit_barrel_draw_etch_marks(DigitBarrel *self) -{ - int iy; - VerticalStrip *strip; - GenericLayer *layer; - - strip = VERTICAL_STRIP(self); - layer = GENERIC_LAYER(self); - - generic_layer_lock(layer); - - Uint32 *pixels = layer->canvas->pixels; - Uint32 color = SDL_UYELLOW(layer->canvas); - float count = 0; - for(float y = self->fei; round(y) < generic_layer_h(layer); y += self->symbol_h/2.0){ - iy = round(y); -// printf("%0.2f y = %d\n",count,iy); - for(int x = 0; x < generic_layer_w(layer); x++){ - pixels[iy * generic_layer_w(layer) + x] = color; - } - count += 5.0; - } - generic_layer_unlock(layer); -} - - diff --git a/digit-barrel.h b/digit-barrel.h deleted file mode 100644 index e3c0f5b..0000000 --- a/digit-barrel.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef DIGIT_BARREL_H -#define DIGIT_BARREL_H - -#include -#include "SDL_pcf.h" - -#include "generic-layer.h" -#include "vertical-strip.h" -#include "misc.h" - -typedef struct{ - SDL_Rect src; - SDL_Rect dst; -}DigitBarrelPatch; - -typedef struct{ - GenericLayer *layer; /*All patches have the same source*/ - /*TODO: Check if we can get away with 2: Is there a case - * when all 3 are needed?*/ - DigitBarrelPatch patches[3]; /*Up to 3: top, middle, bottom*/ - uintf8_t npatches; -}DigitBarrelState; - -typedef struct{ - VerticalStrip super; - - float symbol_h; - float fei; - uintf8_t refcount; -}DigitBarrel; - - -DigitBarrel *digit_barrel_new(PCF_Font *font, float start, float end, float step); -DigitBarrel *digit_barrel_init(DigitBarrel *self, PCF_Font *font, float start, float end, float step); -void digit_barrel_free(DigitBarrel *self); - - -void digit_barrel_draw_etch_marks(DigitBarrel *self); -float digit_barrel_resolve_value(DigitBarrel *self, float value); - -//void digit_barrel_render_value(DigitBarrel *self, float value, BufferedGauge *dst, SDL_Rect *region, float rubis); -void digit_barrel_state_value(DigitBarrel *self, float value, SDL_Rect *region, float rubis, DigitBarrelState *state); -#endif /* DIGIT_BARREL_H */ diff --git a/elevator-gauge.c b/elevator-gauge.c deleted file mode 100644 index 25c3c9f..0000000 --- a/elevator-gauge.c +++ /dev/null @@ -1,286 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include -#include -#include - -#include -#include -#include - -#include "elevator-gauge.h" -#include "misc.h" -#include "res-dirs.h" - -static void elevator_gauge_render(ElevatorGauge *self, Uint32 dt, RenderContext *ctx); -static void elevator_gauge_update_state(ElevatorGauge *self, Uint32 dt); -static void *elevator_gauge_dispose(ElevatorGauge *self); -static BaseGaugeOps elevator_gauge_ops = { - .render = (RenderFunc)elevator_gauge_render, - .update_state = (StateUpdateFunc)elevator_gauge_update_state, - .dispose = (DisposeFunc)elevator_gauge_dispose -}; - -static bool elevator_gauge_build_elevator(ElevatorGauge *self, Uint32 color); - -/** - * @brief Creates a new ElevatorGauge. Calling code is responsible - * for the freeing. - * - * @see elevator_gauge_init for params and return value - */ -ElevatorGauge *elevator_gauge_new(bool marked, Location elevator_location, - PCF_Font *font, SDL_Color color, - float from, float to, float step, - int bar_max_w, int bar_max_h, - int nzones, ColorZone *zones) -{ - ElevatorGauge *self; - bool rv; - - self = calloc(1, sizeof(ElevatorGauge)); - if(self){ - rv = elevator_gauge_init(self, - marked, elevator_location, - font, color, - from, to, step, - bar_max_w, bar_max_h, - nzones, zones); - if(!rv){ - return base_gauge_free(BASE_GAUGE(self)); - } - } - return self; -} - -/** - * @brief Inits a ElevatorGauge - * - * @param self a ElevatorGauge - * @param marked Write values corresponding to hatch marks - * @param location Which side (left or right) to put the elevator relative - * to the ruler. - * @param font The font to use for markings - * @param color the color to use when writing hatch marks and markings - * @param from start of the value range - * @param to end of the value range - * @param step increment in value units (meters, degrees, etc.) of hatch - * marks. Passing in a negative value will create only hatch marks at the - * begining/end of the range. See generic_ruler_init for a discussion of - * valid @p step values. - * @param bar_max_w Maximum width of the bar itself. It can be shrinked to - * accomodate the needed number of hatch marks. - * @param bar_max_h Maximum height of the bar itself. The gauge will be - * larger to accomadate markings (if any) and cursor(s). - * @param nzones size of the @p zones array, 0 if none - * @param zones array of ColorZones that will be used in the gauge. NULL - * for none. - * @return @p self on success, NULL on failure. - * - * @note Array is copied, caller can pass in a temporary local array. - * - * @see generic_ruler_init - * @see elevator_gauge_new - */ -ElevatorGauge *elevator_gauge_init(ElevatorGauge *self, - bool marked, Location elevator_location, - PCF_Font *font, SDL_Color color, - float from, float to, float step, - int bar_max_w, int bar_max_h, - int nzones, ColorZone *zones) -{ - Location marks_location; - Location spine_location; - - self->elevator_location = elevator_location; - marks_location = (self->elevator_location == Left) ? Right : Left; - spine_location = elevator_location; - - generic_ruler_init(&(self->ruler), - RulerVertical, RulerGrowAgainstAxis, - from, to, step, - font, marks_location, 0, - bar_max_w, bar_max_h - ); - SFV_GAUGE(self)->value = from; - - self->nzones = nzones; - self->zones = calloc(self->nzones, sizeof(ColorZone)); - if(!self->zones) - return NULL; - - for(int i = 0; i < nzones; i++){ - self->zones[i] = zones[i]; - } - - Uint32 fcolor; - fcolor = SDL_MapRGBA( - GENERIC_LAYER(&self->ruler)->canvas->format, - color.r, color.g, color.b, color.a - ); - - /*Draws the ruler*/ - bool rv; - if(self->nzones > 0){ - bool rv = generic_ruler_draw_zones(&self->ruler, spine_location, self->nzones, self->zones, 0.7); - if(!rv) - printf("Draw zones failed!\n"); - } - rv = generic_ruler_etch_hatches(&(self->ruler), fcolor, false, true, marks_location); - if(!rv) - printf("Draw etches failed!\n"); - - if(marked && font){ /*Font will also be used to tag the cursors (itf)*/ - rv = generic_ruler_etch_markings(&(self->ruler), marks_location, font, fcolor, 0); - if(!rv) - printf("Draw markings failed!\n"); - } - generic_layer_build_texture(GENERIC_LAYER(&self->ruler)); - - elevator_gauge_build_elevator(self, fcolor); - if(!self->elevator) - return false; - - self->ruler_rect = (SDL_Rect){ - .x = self->elevator->canvas->w, - .y = 0, - .w = GENERIC_LAYER(&self->ruler)->canvas->w, - .h = GENERIC_LAYER(&self->ruler)->canvas->h - }; - - /* TODO: Move me as first operation to ensure that Ops are always - * set when we return NULL so that base_gauge_dispose (called by - * base_gauge_free) can properly dispose any gauge-allocated resources*/ - base_gauge_init(BASE_GAUGE(self), - &elevator_gauge_ops, - GENERIC_LAYER(&self->ruler)->canvas->w + self->elevator->canvas->w, - GENERIC_LAYER(&self->ruler)->canvas->h - ); - - return self; -} - -/** - * @brief Release resources held by @p self. - * - * @param self a ElevatorGauge - */ -static void *elevator_gauge_dispose(ElevatorGauge *self) -{ - generic_ruler_dispose(&self->ruler); - if(self->elevator) - generic_layer_free(self->elevator); - if(self->zones) - free(self->zones); - - return self; -} - -bool elevator_gauge_set_value(ElevatorGauge *self, float value, bool animated) -{ - bool rv = true; - BaseAnimation *animation; - - generic_ruler_clip_value(&self->ruler, &value); - - return sfv_gauge_set_value(SFV_GAUGE(self), value, animated); -} - -/* - * @brief Creates the elevator bitmap - * - * INTERNAL USE ONLY - * - * TODO: Generate the cursor otf without using files - */ -static bool elevator_gauge_build_elevator(ElevatorGauge *self, Uint32 color) -{ - char *filename; - int startx, endx; - - if(self->elevator_location != Left && self->elevator_location != Right){ - printf("Unsupported location\n"); - return false; - } - - filename = (self->elevator_location == Left) ? IMG_DIR"/lh-cursor10.png" : IMG_DIR"/rh-cursor10.png"; - - SDL_Surface *triangle = IMG_Load(filename); - if(!triangle) - return NULL; - SDL_SetSurfaceBlendMode(triangle, SDL_BLENDMODE_NONE); - - self->elevator = generic_layer_new(triangle->w, self->ruler.ruler_area.h); - if(!self->elevator) - return NULL; - - /*Blit triangle at top left of elevator*/ - SDL_BlitSurface(triangle, NULL, self->elevator->canvas, NULL); - SDL_FreeSurface(triangle); - /*Creates the 'tail'*/ - startx = (self->elevator_location == Left) - ? 0 - : self->elevator->canvas->w - 4; - endx = (self->elevator_location == Left) - ? 4 - : self->elevator->canvas->w; - generic_layer_lock(self->elevator); - Uint32 *pixels = self->elevator->canvas->pixels; - for(int y = 4; y < self->elevator->canvas->h; y++){ - for(int x = startx; x < endx; x++) - pixels[y * self->elevator->canvas->w + x] = color; - } - generic_layer_unlock(self->elevator); - - generic_layer_build_texture(self->elevator); - - return true; -} - -static void elevator_gauge_update_state(ElevatorGauge *self, Uint32 dt) -{ - int yinc; - int elevator_top; - - yinc = generic_ruler_get_pixel_increment_for(&self->ruler, SFV_GAUGE(self)->value); - elevator_top = SDLExt_RectLastY(&self->ruler.ruler_area) - yinc; - - /*Area to copy from the whole elevator image*/ - self->state.elevator_src = (SDL_Rect){ - .x = 0, - .y = 0, - .w = self->elevator->canvas->w, - .h = yinc + 1 - }; - /*Where to put it*/ - self->state.elevator_dst = (SDL_Rect){ - .x = (self->elevator_location == Left) - ? 0 - : SDLExt_RectLastX(&self->ruler_rect) + 1, - .y = self->ruler_rect.y + elevator_top, - .w = self->state.elevator_src.w, - .h = self->state.elevator_src.h - }; - -} - -static void elevator_gauge_render(ElevatorGauge *self, Uint32 dt, RenderContext *ctx) -{ - base_gauge_blit_layer(BASE_GAUGE(self), ctx, - GENERIC_LAYER(&self->ruler), - NULL, - &self->ruler_rect - ); - - base_gauge_blit_layer(BASE_GAUGE(self), ctx, - self->elevator, - &self->state.elevator_src, - &self->state.elevator_dst - ); -} diff --git a/elevator-gauge.h b/elevator-gauge.h deleted file mode 100644 index 6a0250d..0000000 --- a/elevator-gauge.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef ELEVATOR_GAUGE_H -#define ELEVATOR_GAUGE_H - -#include "sfv-gauge.h" -#include "generic-layer.h" -#include "generic-ruler.h" - -typedef struct{ - SDL_Rect elevator_src; - SDL_Rect elevator_dst; -}ElevatorGaugeState; - -typedef struct{ - SfvGauge super; - - GenericRuler ruler; - Uint32 color; - - GenericLayer *elevator; - Location elevator_location; - - ColorZone *zones; - uint8_t nzones; - - /* Ruler offset within the gauge - * Cursor base being at y = 0 - * Simple ints would have done but the blitting - * functions need SDL_Rects - */ - SDL_Rect ruler_rect; - - ElevatorGaugeState state; -}ElevatorGauge; - -ElevatorGauge *elevator_gauge_new(bool marked, Location elevator_location, - PCF_Font *font, SDL_Color color, - float from, float to, float step, - int bar_max_w, int bar_max_h, - int nzones, ColorZone *zones); -ElevatorGauge *elevator_gauge_init(ElevatorGauge *self, - bool marked, Location elevator_location, - PCF_Font *font, SDL_Color color, - float from, float to, float step, - int bar_max_w, int bar_max_h, - int nzone, ColorZone *zones); - -bool elevator_gauge_set_value(ElevatorGauge *self, float value, bool animated); -#endif /* ELEVATOR_GAUGE_H */ diff --git a/fg-data-source.c b/fg-data-source.c deleted file mode 100644 index a559915..0000000 --- a/fg-data-source.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include -#include -#include -#include -#include -#include - -#include "data-source.h" -#include "fg-data-source.h" - -static bool fg_data_source_frame(FGDataSource *self, uint32_t dt); -static FGDataSource *fg_data_source_dispose(FGDataSource *self); -static DataSourceOps fg_data_source_ops = { - .frame = (DataSourceFrameFunc)fg_data_source_frame, - .dispose = (DataSourceDisposeFunc)fg_data_source_dispose -}; - -FGDataSource *fg_data_source_new(int port) -{ - FGDataSource *self; - - self = calloc(1, sizeof(FGDataSource)); - if(self){ - if(!fg_data_source_init(self, port)){ - free(self); - return NULL; - } - } - return self; -} - -FGDataSource *fg_data_source_init(FGDataSource *self, int port) -{ - if(!data_source_init(DATA_SOURCE(self), &fg_data_source_ops)) - return NULL; - - self->fglink = flightgear_connector_new(port); - if(!self->fglink) - return NULL; - flightgear_connector_set_nonblocking(self->fglink); - - self->port = port; - return self; -} - -void fg_data_source_banner(FGDataSource *self) -{ - struct ifaddrs * ifAddrStruct=NULL; - struct ifaddrs * ifa=NULL; - void * tmpAddrPtr=NULL; - - getifaddrs(&ifAddrStruct); - - - printf("Waiting for first packet from FlightGear\n"); - printf("Be sure to:\n"); - printf("1. have basic_proto.xml in $FG_ROOT/Protocol\n"); - printf("2. Run FlightGear(fgfs) with --generic=socket,out,5,%sLOCAL_IP%s,%d,udp,basic_proto\n", - "\x1B[1;31m", - "\x1B[0m", - self->port - ); - printf("Be sure to replace %sLOCAL_IP%s with the IP of the local machine, one of:\n", - "\x1B[1;31m", - "\x1B[0m" - ); - - getifaddrs(&ifAddrStruct); - for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) { - if (!ifa->ifa_addr) { - continue; - } - if (ifa->ifa_addr->sa_family == AF_INET) { // check it is IP4 - // is a valid IP4 Address - tmpAddrPtr=&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; - char addressBuffer[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN); - if(!strcmp(ifa->ifa_name, "lo")) continue; - printf("\t%s IP Address %s\n", ifa->ifa_name, addressBuffer); - } - } - if (ifAddrStruct!=NULL) freeifaddrs(ifAddrStruct); -} - -static FGDataSource *fg_data_source_dispose(FGDataSource *self) -{ - if(self->fglink) - flightgear_connector_free(self->fglink); - return self; -} - -static bool fg_data_source_frame(FGDataSource *self, uint32_t dt) -{ - FlightgearPacket packet; - bool rv; - - rv = flightgear_connector_get_packet(self->fglink, &packet); - if(!rv) - return false; - - data_source_set_location( - DATA_SOURCE(self), &(LocationData){ - .super.latitude = packet.latitude, - .super.longitude = packet.longitude, - .altitude = packet.altitude - } - ); - - data_source_set_dynamics( - DATA_SOURCE(self), &(DynamicsData){ - .airspeed = packet.airspeed, - .vertical_speed = packet.vertical_speed, - .slip_rad = packet.side_slip - } - ); - - data_source_set_attitude( - DATA_SOURCE(self), &(AttitudeData){ - .roll = packet.roll, - .pitch = packet.pitch, - .heading = packet.heading - } - ); - - data_source_set_engine_data( - DATA_SOURCE(self), &(EngineData){ - .rpm = packet.rpm, - .fuel_flow = packet.fuel_flow, - .oil_temp = packet.oil_temp, - .oil_press = packet.oil_px, - .cht = packet.cht, - .fuel_px = packet.fuel_px, - .fuel_qty = packet.fuel_qty - } - ); - - DATA_SOURCE(self)->has_fix = true; - - return true; -} diff --git a/fg-data-source.h b/fg-data-source.h deleted file mode 100644 index 2d13f8e..0000000 --- a/fg-data-source.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef FG_DATA_SOURCE_H -#define FG_DATA_SOURCE_H - -#include "data-source.h" -#include "flightgear-connector.h" - -typedef struct{ - DataSource super; - - FlightgearConnector *fglink; - int port; -}FGDataSource; - -FGDataSource *fg_data_source_new(int port); -FGDataSource *fg_data_source_init(FGDataSource *self, int port); - -void fg_data_source_banner(FGDataSource *self); -#endif /* FG_DATA_SOURCE_H */ diff --git a/fg-io b/fg-io deleted file mode 160000 index cda8e33..0000000 --- a/fg-io +++ /dev/null @@ -1 +0,0 @@ -Subproject commit cda8e3386b2e7be64d896a14d132eaa33beac3e8 diff --git a/fg-roam b/fg-roam deleted file mode 160000 index f3565ad..0000000 --- a/fg-roam +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f3565ad8e9d536832b6e54dc29d28f6db5ad877c diff --git a/fg-tape-data-source.c b/fg-tape-data-source.c deleted file mode 100644 index cef9ade..0000000 --- a/fg-tape-data-source.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include - -#include "data-source.h" -#include "fg-tape-data-source.h" - -/*private struct*/ -typedef struct{ - double latitude; - double longitude; - double altitude; - float roll; - float pitch; - float heading; - float slip_rad; - float airspeed; //kts - float vertical_speed; //vertical speed //feets per second - - float rpm; - float fuel_flow; - float oil_temp; - float oil_press; - float cht; - float fuel_px; - float fuel_qty; -}TapeRecord; - - - -static bool fg_tape_data_source_frame(FGTapeDataSource *self, uint32_t dt); -static FGTapeDataSource *fg_tape_data_source_dispose(FGTapeDataSource *self); -static DataSourceOps fg_tape_data_souce_ops = { - .frame = (DataSourceFrameFunc)fg_tape_data_source_frame, - .dispose = (DataSourceDisposeFunc)fg_tape_data_source_dispose -}; - - - -FGTapeDataSource *fg_tape_data_source_new(char *filename, int start_pos) -{ - FGTapeDataSource *self; - - self = calloc(1, sizeof(FGTapeDataSource)); - if(self){ - if(!fg_tape_data_souce_init(self, filename, start_pos)){ - data_source_free(DATA_SOURCE(self)); - return NULL; - } - } - return self; -} - -FGTapeDataSource *fg_tape_data_souce_init(FGTapeDataSource *self, char *filename, int start_pos) -{ - int found; - - if(!data_source_init(DATA_SOURCE(self), &fg_tape_data_souce_ops)) - return NULL; - - self->tape = fg_tape_new_from_file(filename); - if(!self->tape) - return NULL; -// fg_tape_dump(tape); -// - found = fg_tape_get_signals(self->tape, self->signals, - "/position[0]/latitude-deg[0]", - "/position[0]/longitude-deg[0]", - "/position[0]/altitude-ft[0]", - "/orientation[0]/roll-deg[0]", - "/orientation[0]/pitch-deg[0]", - "/orientation[0]/heading-deg[0]", - "/orientation[0]/side-slip-rad[0]", - "/velocities[0]/airspeed-kt[0]", - "/velocities[0]/vertical-speed-fps[0]", - "/engines[0]/engine[0]/rpm[0]", - "/engines[0]/engine[0]/fuel-flow-gph[0]", - "/engines[0]/engine[0]/oil-temperature-degf[0]", - "/engines[0]/engine[0]/oil-pressure-psi[0]", - "/engines[0]/engine[0]/cht-degf[0]", - "/engines[0]/engine[0]/fuel-px-psi[0]", - "/consumables[0]/fuel[0]/tank[0]/level-gal_us[0]", - NULL - ); - printf("TapeRecord: found %d out of %d signals\n",found, 16); - - self->position = start_pos * 1000; /*Starting position in the tape*/ - self->playing= true; - - return self; -} - -static FGTapeDataSource *fg_tape_data_source_dispose(FGTapeDataSource *self) -{ - if(self->tape) - fg_tape_free(self->tape); - return self; -} - -static bool fg_tape_data_source_frame(FGTapeDataSource *self, uint32_t dt) -{ - TapeRecord record; - int rv; - - if(dt != 0 && dt < (1000/25)) //One update per 1/25 second - return false; - - if(!self->playing) - return false; - - self->position += dt; - rv = fg_tape_get_data_at(self->tape, self->position / 1000.0, 16, self->signals, &record); - if(rv <= 0) - return false; /*Error or end of tape*/ - - - data_source_set_location( - DATA_SOURCE(self), &(LocationData){ - .super.latitude = record.latitude, - .super.longitude = record.longitude, - .altitude = record.altitude - } - ); - - data_source_set_dynamics( - DATA_SOURCE(self), &(DynamicsData){ - .airspeed = record.airspeed, - .vertical_speed = record.vertical_speed, - .slip_rad = record.slip_rad - } - ); - - data_source_set_attitude( - DATA_SOURCE(self), &(AttitudeData){ - .roll = record.roll, - .pitch = record.pitch, - .heading = record.heading - } - ); - - data_source_set_engine_data( - DATA_SOURCE(self), &(EngineData){ - .rpm = record.rpm, - .fuel_flow = record.fuel_flow, - .oil_temp = record.oil_temp, - .oil_press = record.oil_press, /*TODO: All to _px*/ - .cht = record.cht, - .fuel_px = record.fuel_px, - .fuel_qty = record.fuel_qty - } - ); - - DATA_SOURCE(self)->has_fix = true; - - return true; -} diff --git a/fg-tape-data-source.h b/fg-tape-data-source.h deleted file mode 100644 index 89d168f..0000000 --- a/fg-tape-data-source.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef FG_TAPE_DATA_SOURCE_H -#define FG_TAPE_DATA_SOURCE_H -#include -#include - -#include "data-source.h" -#include "fg-tape.h" - -typedef struct{ - DataSource super; - - FGTape *tape; - FGTapeSignal signals[16]; - - uint32_t position; - bool playing; -}FGTapeDataSource; - -FGTapeDataSource *fg_tape_data_source_new(char *filename, int start_pos); -FGTapeDataSource *fg_tape_data_souce_init(FGTapeDataSource *self, char *filename, int start_pos); - - -#endif /* FG_TAPE_DATA_SOURCE_H */ diff --git a/fishbone-gauge.c b/fishbone-gauge.c deleted file mode 100644 index 17aba5d..0000000 --- a/fishbone-gauge.c +++ /dev/null @@ -1,228 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include -#include -#include - -#include -#include - -#include "SDL_rect.h" -#include "base-gauge.h" -#include "fishbone-gauge.h" - -#include "generic-ruler.h" -#include "resource-manager.h" -#include "sdl-colors.h" -#include "SDL_pcf.h" -#include "misc.h" -#include "res-dirs.h" - -#define view_set_pixel(surface, x, y, color) (Uint32 *)((surface)->pixels)[(y)*(surface)->width+(x)] = (color) - -static void fishbone_gauge_render(FishboneGauge *self, Uint32 dt, RenderContext *ctx); -static void fishbone_gauge_update_state(FishboneGauge *self, Uint32 dt); -static void *fishbone_gauge_dispose(FishboneGauge *self); -static BaseGaugeOps fishbone_gauge_ops = { - .render = (RenderFunc)fishbone_gauge_render, - .update_state = (StateUpdateFunc)fishbone_gauge_update_state, - .dispose = (DisposeFunc)fishbone_gauge_dispose -}; - - -/** - * @brief Creates a new FishboneGauge. Calling code is responsible - * for the freeing. - * - * @see fishbone_gauge_init for params and return value - */ -FishboneGauge *fishbone_gauge_new(bool marked, - PCF_Font *font, SDL_Color color, - float from, float to, float step, - int bar_max_w, int bar_max_h, - int nzones, ColorZone *zones) -{ - FishboneGauge *self; - bool rv; - - self = calloc(1, sizeof(FishboneGauge)); - if(self){ - rv = fishbone_gauge_init(self, marked, - font, color, - from, to, step, - bar_max_w, bar_max_h, - nzones, zones); - if(!rv){ - return base_gauge_free(BASE_GAUGE(self)); - } - } - return self; -} - -/** - * @brief Inits a FishboneGauge - * - * @param self a FishboneGauge - * @param marked Write values corresponding to hatch marks - * @param font The font to use for markings - * @param color the color to use when writing hatch marks and markings - * @param from start of the value range - * @param to end of the value range - * @param step increment in value units (meters, degrees, etc.) of hatch - * marks. Passing in a negative value will create only hatch marks at the - * begining/end of the range. See generic_ruler_init for a discussion of - * valid @p step values. - * @param bar_max_w Maximum width of the bar itself. It can be shrinked to - * accomodate the needed number of hatch marks. - * @param bar_max_h Maximum height of the bar itself. The gauge will be - * larger to accomadate markings (if any) and cursor(s). - * @param nzones size of the @p zones array, 0 if none - * @param zones array of ColorZones that will be used in the gauge. NULL - * for none. - * @return @p self on success, NULL on failure. - * - * @note Array is copied, caller can pass in a temporary local array. - * - * @see generic_ruler_init - * @see fishbone_gauge_new - */ -FishboneGauge *fishbone_gauge_init(FishboneGauge *self, - bool marked, - PCF_Font *font, SDL_Color color, - float from, float to, float step, - int bar_max_w, int bar_max_h, - int nzones, ColorZone *zones) -{ - - generic_ruler_init(&(self->ruler), - RulerHorizontal, RulerGrowAlongAxis, - from, to, step, - font, Bottom, 0, - bar_max_w, bar_max_h - ); - - self->nzones = nzones; - self->zones = calloc(self->nzones, sizeof(ColorZone)); - if(!self->zones) - return NULL; - - for(int i = 0; i < nzones; i++){ - self->zones[i] = zones[i]; - } - - Uint32 fcolor; - fcolor = SDL_MapRGBA( - GENERIC_LAYER(&self->ruler)->canvas->format, - color.r, color.g, color.b, color.a - ); - - /*Draws the ruler*/ - if(self->nzones > 0){ - generic_ruler_draw_zones(&self->ruler, Center, self->nzones, self->zones, 0.7); - } - generic_ruler_etch_hatches(&(self->ruler), fcolor, false, true, Center); - if(marked && font) /*Font will also be used to tag the cursors (itf)*/ - generic_ruler_etch_markings(&(self->ruler), Bottom, font, fcolor, 0); - generic_layer_build_texture(GENERIC_LAYER(&self->ruler)); - - /* Loads the cursor. - * TODO: Support 2 cursors and generate them otf - * to match the font size. Have the ability to enclose - * a letter within the triangle. - */ - self->cursor = generic_layer_new_from_file(IMG_DIR"/fishbone-cursor.png"); - if(!self->cursor) - return NULL; - generic_layer_build_texture(self->cursor); - - int extra_h = SDLExt_RectMidY(&self->ruler.ruler_area) - self->cursor->canvas->w; - /*Does Cursor go out of the area?*/ - extra_h = (extra_h < 0) ? abs(extra_h) : 0; - /* Check if the cursor goes outside of the ruler area when at it's leftmost - * position. - * TODO: Support GrowAgainstAxis*/ - int first_etch = generic_ruler_get_pixel_increment_for(&self->ruler, self->ruler.start); - int delta = self->ruler.ruler_area.x - first_etch - generic_layer_w(self->cursor)/2; - delta = (delta < 0) ? abs(delta) : 0; - self->ruler_rect = (SDL_Rect){ - .x = delta, - .y = extra_h, - .w = GENERIC_LAYER(&self->ruler)->canvas->w, - .h = GENERIC_LAYER(&self->ruler)->canvas->h - }; - self->state.cursor_rect = (SDL_Rect){ - .x = 0, - .y = 0, - .w = self->cursor->canvas->w, - .h = self->cursor->canvas->h - }; - - /* TODO: Move me as first operation to ensure that Ops are always - * set when we return NULL so that base_gauge_dispose (called by - * base_gauge_free) can properly dispose any gauge-allocated resources*/ - base_gauge_init(BASE_GAUGE(self), - &fishbone_gauge_ops, - GENERIC_LAYER(&self->ruler)->canvas->w, - GENERIC_LAYER(&self->ruler)->canvas->h + extra_h - ); - - return self; -} - -/** - * @brief Release resources held by @p self. - * - * @param self a FishboneGauge - */ -static void *fishbone_gauge_dispose(FishboneGauge *self) -{ - generic_ruler_dispose(&self->ruler); - if(self->cursor) - generic_layer_free(self->cursor); - if(self->zones) - free(self->zones); - - return self; -} - -bool fishbone_gauge_set_value(FishboneGauge *self, float value, bool animated) -{ - bool rv = true; - BaseAnimation *animation; - - generic_ruler_clip_value(&self->ruler, &value); - - return sfv_gauge_set_value(SFV_GAUGE(self), value, animated); -} - -static void fishbone_gauge_update_state(FishboneGauge *self, Uint32 dt) -{ - int xinc; - int cursor_center; - - xinc = generic_ruler_get_pixel_increment_for(&self->ruler, SFV_GAUGE(self)->value); - - cursor_center = self->cursor->canvas->w/2; - - self->state.cursor_rect.x = (self->ruler.ruler_area.x + xinc) - + self->ruler_rect.x - - cursor_center; -} - -static void fishbone_gauge_render(FishboneGauge *self, Uint32 dt, RenderContext *ctx) -{ - base_gauge_blit_layer(BASE_GAUGE(self), ctx, - GENERIC_LAYER(&self->ruler), - NULL, - &self->ruler_rect); - base_gauge_blit_layer(BASE_GAUGE(self), ctx, - self->cursor, - NULL, - &self->state.cursor_rect); -} diff --git a/fishbone-gauge.h b/fishbone-gauge.h deleted file mode 100644 index eaafad7..0000000 --- a/fishbone-gauge.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef FISHBONE_GAUGE_H -#define FISHBONE_GAUGE_H - -#include "sfv-gauge.h" -#include "generic-layer.h" -#include "generic-ruler.h" - -typedef struct{ - /* Ruler offset within the gauge - * Cursor base being at y = 0 - * Simple ints would have done but the blitting - * functions need SDL_Rects - */ - SDL_Rect cursor_rect; -}FishboneGaugeState; - -typedef struct{ - SfvGauge super; - - float value; - - GenericRuler ruler; - Uint32 color; - - /* TODO: Generate cursors otf, and support - * 2 cursors, one of each side of the scale. - * */ - GenericLayer *cursor; - - ColorZone *zones; - uint8_t nzones; - - /* Ruler offset within the gauge - * Cursor base being at y = 0 - * Simple ints would have done but the blitting - * functions need SDL_Rects - */ - SDL_Rect ruler_rect; - - FishboneGaugeState state; -}FishboneGauge; - -FishboneGauge *fishbone_gauge_new(bool marked, - PCF_Font *font, SDL_Color color, - float from, float to, float step, - int bar_max_w, int bar_max_h, - int nzones, ColorZone *zones); -FishboneGauge *fishbone_gauge_init(FishboneGauge *self, - bool marked, - PCF_Font *font, SDL_Color color, - float from, float to, float step, - int bar_max_w, int bar_max_h, - int nzone, ColorZone *zones); - -bool fishbone_gauge_set_value(FishboneGauge *self, float value, bool animated); -#endif /* FISHBONE_GAUGE_H */ diff --git a/generic-layer.c b/generic-layer.c deleted file mode 100644 index 6f571c1..0000000 --- a/generic-layer.c +++ /dev/null @@ -1,263 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include - -#include -#include - -#include "generic-layer.h" - -#include "SDL_gpu.h" - -/** - * GenericLayer: A class to manage drawing areas (SDL_Surfaces) - * that will be drawn on (or loaded from file) and then be used as-is - * without further modification and optionaly turned into textures. - * - * This is intended to be used for anything that must be blit to the - * screen each frame. - * - */ - - -/** - * @brief Creates a new GenericLayer of given size. - * - * The GenericLayer returned must be freed by the calling code. - * - * @param width canvas width - * @param height canvas width - * @return a newly allocated GenericLayer on success, NULL on failure. - * - * @see generic_layer_free - */ -GenericLayer *generic_layer_new(int width, int height) -{ - GenericLayer *self; - - self = calloc(1, sizeof(GenericLayer)); - if(self){ - if(!generic_layer_init(self, width, height)){ - generic_layer_dispose(self); - return NULL; - } - } - return self; -} - -/** - * @brief Creates a new GenericLayer from an existing image. Loading is - * done through SDL_Image, refer to their documention for format support. - * - * The GenericLayer returned must be freed by the calling code. - * - * @param filaname The image to load - * @return a newly allocated GenericLayer on success, NULL on failure. - * - * @see generic_layer_free - */ -GenericLayer *generic_layer_new_from_file(const char *filename) -{ - GenericLayer *self; - - self = calloc(1, sizeof(GenericLayer)); - if(self){ - if(!generic_layer_init_from_file(self, filename)){ - generic_layer_dispose(self); - return NULL; - } - } - return self; -} - -/** - * @brief Creates the underlying canvas (SDL_Surface) - * - * After calling this function successfuly, the canvas (self->canvas) - * can be accessed and drawed on. - * - * @param self a GenericLayer - * @param width the width of the canvas - * @param height the height of the canvas - * @return true on success, false otherwise. If the function returns - * false, the canvas is not suitable for use/access. - * - */ -bool generic_layer_init(GenericLayer *self, int width, int height) -{ - self->canvas = SDL_CreateRGBSurfaceWithFormat( - 0, - width, height, - 32, SDL_PIXELFORMAT_RGBA32 - ); -/*TODO: Is this useful? Enclosing object would have memeset'ed itself*/ -#if USE_SDL_GPU - self->texture = NULL; -#endif - return self->canvas != NULL; -} - -/** - * @brief Creates the underlying canvas (SDL_Surface) with the specified mask. - * - * After calling this function successfuly, the canvas (self->canvas) can be - * accessed and drawed on. - * - * @note All GenericLayer surfaces will/must have a depth of 32 bits per pixel. - * - * @param self a GenericLayer - * @param width the width of the canvas - * @param height the height of the canvas - * @param Rmask the red mask for the pixels - * @param Gmask the green mask for the pixels - * @param Bmask the blue mask for the pixels - * @param Amask the alpha mask for the pixels - * @return true on success, false otherwise. If the function returns - * false, the canvas is not suitable for use/access. - */ -bool generic_layer_init_with_masks(GenericLayer *self, int width, int height, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask) -{ - self->canvas = SDL_CreateRGBSurface( - 0, - width, height, - 32, - Rmask, Gmask, Bmask, Amask - ); -/*TODO: Is this useful? Enclosing object would have memeset'ed itself*/ -#if USE_SDL_GPU - self->texture = NULL; -#endif - return self->canvas != NULL; -} - - -/** - * @brief Release the resources held by self. - * - * @param self a GenericLayer - */ -void generic_layer_dispose(GenericLayer *self) -{ - if(self->canvas) - SDL_FreeSurface(self->canvas); -#if USE_SDL_GPU - if(self->texture) - GPU_FreeImage(self->texture); -#endif -} - -/** - * @brief Release any resource held by and free - * the memory used by @p self. - * - * @param self a GenericLayer - */ -void generic_layer_free(GenericLayer *self) -{ - generic_layer_dispose(self); - free(self); -} - -/** - * @brief Prevent others to remove @p self from under - * your feets. - * - * Match call with generic_layer_unref when you're done. - * - * @param self a GenericLayer - * - * @see generic_layer_unref - */ -/*TODO: Use inderlying refcounts from SDL_Surface/GPU_Image?*/ -/*TODO: inline*/ -void generic_layer_ref(GenericLayer *self) -{ - self->refcount++; -} - -/** - * @brief Matching call to generic_layer_ref. Frees the memory - * when refcount reaches 0 - * - * @param self a GenericLayer - * - * @see generic_layer_ref - * - */ -void generic_layer_unref(GenericLayer *self) -{ - if(--self->refcount == 0){ - generic_layer_free(self); - } -} - -/** - * @brief Loads a file into a newly-created/uninited GenericLayer. - * - * Supported formats are those supported by SDL_Image which does the loading. - * @p self is assumed to be non-inited: No checks are made, no resources - * are freed. - * - * @param self a GenericLayer - * @param filename The file to read from. - * @return true on success, false otherwise. The error - as set by SDL_Image - - * can be retrieved through SDL_GetError. - */ -bool generic_layer_init_from_file(GenericLayer *self, const char *filename) -{ - self->canvas = IMG_Load(filename); -#if USE_SDL_GPU - self->texture = NULL; -#endif - return self->canvas != NULL; -} - - -/** - * @brief Creates a texture from the canvas. - * - * @param self a GenericLayer - * @return true on success, false otherwise. - * - * @note If no texture support is built, this - * funtion will always return true. - * TODO: Get rid of the surface ? - */ -bool generic_layer_build_texture(GenericLayer *self) -{ -#if USE_SDL_GPU - self->texture = GPU_CopyImageFromSurface(self->canvas); - return self->texture != NULL; -#else - return true; -#endif -} - -/** - * @brief Updates the texture from the content of the canvas. - * - * Must be called when you want any modifications done to the - * surface done after the call to generic_layer_build_texture - * to be visible by the GPU. - * - * @param self a GenericLayer - * - * @see generic_layer_build_texture - */ -void generic_layer_update_texture(GenericLayer *self) -{ -#if USE_SDL_GPU - if(self->texture) - GPU_UpdateImage(self->texture, NULL, self->canvas, NULL); - else - generic_layer_build_texture(self); -#endif -} - - diff --git a/generic-layer.h b/generic-layer.h deleted file mode 100644 index 3db8e2b..0000000 --- a/generic-layer.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef GENERIC_LAYER_H -#define GENERIC_LAYER_H -#include "misc.h" -#include - -#include - -#if USE_SDL_GPU -#include -#endif - -typedef struct{ - uintf8_t refcount; - SDL_Surface *canvas; -#if USE_SDL_GPU - GPU_Image *texture; -#endif -}GenericLayer; - -#define GENERIC_LAYER(self) ((GenericLayer *)(self)) -#define generic_layer_lock(self) SDL_LockSurface((self)->canvas) -#define generic_layer_unlock(self) SDL_UnlockSurface((self)->canvas) - -#define generic_layer_w(self) ((self)->canvas->w) -#define generic_layer_h(self) ((self)->canvas->h) - -GenericLayer *generic_layer_new(int width, int height); -GenericLayer *generic_layer_new_from_file(const char *filename); - -bool generic_layer_init(GenericLayer *self, int width, int height); -bool generic_layer_init_with_masks(GenericLayer *self, int width, int height, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask); -bool generic_layer_init_from_file(GenericLayer *self, const char *filename); - -void generic_layer_dispose(GenericLayer *self); -void generic_layer_free(GenericLayer *self); - -void generic_layer_ref(GenericLayer *self); -void generic_layer_unref(GenericLayer *self); - -bool generic_layer_build_texture(GenericLayer *self); -void generic_layer_update_texture(GenericLayer *self); -#endif /* GENERIC_LAYER_H */ diff --git a/generic-ruler.c b/generic-ruler.c deleted file mode 100644 index ca6e671..0000000 --- a/generic-ruler.c +++ /dev/null @@ -1,584 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include - -#include "generic-ruler.h" - -#include "SDL_surface.h" -#include "generic-layer.h" -#include "misc.h" -#include "view.h" - -#define TEXT_SPACE 4 - - -bool generic_ruler_get_size_request(GenericRuler *self, int8_t precision, PCF_Font *font, Location markings_location, int *w, int *h); - -/** - * @brief Init a ruler that maps a range that goes from @p start (included) to - * @p end (included) to a pixel region that can be either vertical or horizontal. - * The region maximum size is specified with @p ruler_w and @p ruler_h. - * Depending on the ruler direction, one of these two dimensions will be mapped - * to the value range. It can be shrinked to match the nearest multiple of @p - * step so that the last hatch mark lands on the last pixel of the range. - * - * The ruler can visually (@p direction) go either way, but the range must - * always be specified as from being lower than to. - * - * @warning @p step must be either -1 (one big step from @p start to @p end) or - * a divider of @p end, e.g: - * from to step valid - * 0 25 5 yes 25 = 5*5 -> 5 marks, interval walked in 5 steps - * 0 25 1 yes 25 = 25*1 -> 25marks, interval walked in 25 steps - * 0 25 2 NO 25 = 12.5 * 2 -> not a integeral number of marks - * - * @param start First (lower) value of the range to map. - * @param end Last(highier) value of the range to map - * @param step Hatch marks spacing. e.g. from = 0, to = 25, step = 5 will - * map a range from 0 to 25 with marks at every 5 units to @p ruler_w pixels if - * @p orientation is RulerHorizontal and to @p ruler_h pixels if orientation is - * RulerVertical. A negative value will disable intermediate hatching. - * @param marks_font The PCF_Font that will be used for markings. NULL If no - * markings are to be drawn. - * @param marks_location Where the markings will be drawn, used to compute the - * full dimensions needed by the ruler itself plus its eventual markings. - * @param markings_precision How many digital places will be written for - * each marking. 0 For integral part only. - * @param ruler_w Maximum width of the ruler, can be modified to represent the - * range and accomodate for markings. Pass NONE if you aren't goint to use the - * markings-etching features of GenericRuler. - * @param ruler_h Maximum height of the ruler, can be modified to represent the - * range and accomodate for markings - * - * @see draw_markings - * - */ -GenericRuler *generic_ruler_init(GenericRuler *self, - RulerOrientation orientation, - RulerDirection direction, - float start, float end, float step, - PCF_Font *markings_font, - Location markings_location, - int8_t markings_precision, - int ruler_w, int ruler_h) -{ - int fullw, fullh; - - self->orientation = orientation; - self->direction = direction; - self->ruler_area.w = ruler_w; - self->ruler_area.h = ruler_h; - - self->start = start; - self->end = end; - if(self->end < self->start){ - printf("%s: self->end(%f) must be greather than self->start(%f).", - __FUNCTION__, self->end, self->start - ); - return NULL; - } - - self->hatch_step = (step > 0) ? step : self->end; - if(fmodf(self->end,self->hatch_step) != 0){ - printf("Warning: range end (%f) is not a multiple of hatch_step(%f), rendering will break\n", - self->end, - self->hatch_step - ); - } - - /*Sophie's algorithm*/ - int nintervals = (self->end - self->start) / self->hatch_step; - int nbars = nintervals + 1; - int pix_available = (self->orientation == RulerHorizontal) ? - ruler_w - (nbars*1) // each bar is 1px wide/tall - : ruler_h - (nbars*1); - int interval_pix_size = pix_available/nintervals; //This is the best interval(number of pixels BETWEEN two etches) size in px. - - /* interval pix size is the number of pixels between bars, - * +1 includes the closing bar */ - self->ppv = (interval_pix_size+1) / self->hatch_step; - if(self->orientation == RulerHorizontal) - self->ruler_area.w = interval_pix_size * nintervals + (nbars*1); //Each bar is 1px wide - else - self->ruler_area.h = interval_pix_size * nintervals + (nbars*1); - - if(markings_font != NULL && markings_location != LocationNone){ - generic_ruler_get_size_request(self, markings_precision, markings_font, markings_location, &fullw, &fullh); - }else{ - fullw = self->ruler_area.w; - fullh = self->ruler_area.h; - } - - generic_layer_init(GENERIC_LAYER(self), fullw, fullh); - - return self; -} - -/** - * @brief Release resources held by @p self. - * - * @param self a GenericRuler - */ -void generic_ruler_dispose(GenericRuler *self) -{ - generic_layer_dispose(GENERIC_LAYER(self)); -} - -/** - * @brief compute how much an area has to grow to accomodate the ruler itself plus - * the markings aroud it. - * - * @warning This functions modifies self->ruler_area. - * - * @param self a GenericRuler - * @param font a The PCF_Font that'll be used for markings - * @param markings_location Where the markings will be put relatively to - * the ruler - * @param w Where to put the computed needed width - * @param h Where to put the computed needed height - * @return true on success, false otherwise - * - */ -#if __GNUC__ >= 8 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wformat-truncation" -#endif -bool generic_ruler_get_size_request(GenericRuler *self, int8_t precision, PCF_Font *font, Location markings_location, int *w, int *h) -{ - int pixel_increment = roundf(self->hatch_step * self->ppv); - - int glyph_height = PCF_FontCharHeight(font); - - char vbuffer[10]; /*9999999999 or 999999999 with a floating dot*/ - SDL_Rect m_rect; //mark rect - - /*Pixels to add on each side of the Fishbone to - * accomodate etching marks - * */ - int left, right; - int top, bottom; - - int fbw = self->ruler_area.w; - int fbh = self->ruler_area.h; - - left = right = top = bottom = 0; - if(self->orientation == RulerHorizontal){ - if(self->direction == RulerGrowAlongAxis){ - snprintf(vbuffer, 10, "%*g", precision, self->start); - PCF_FontGetSizeRequestRect(font, vbuffer, false, &m_rect); - left = SDLExt_RectMidX(&m_rect) - m_rect.x; //We need 'left' more pixels on the left - - snprintf(vbuffer, 10, "%*g", precision, self->end); - PCF_FontGetSizeRequestRect(font, vbuffer, false, &m_rect); - right = SDLExt_RectLastX(&m_rect) - SDLExt_RectMidX(&m_rect);//We need 'right' more pixels on the right - }else{ - snprintf(vbuffer, 10, "%*g", precision, self->end); - PCF_FontGetSizeRequestRect(font, vbuffer, false, &m_rect); - left = SDLExt_RectMidX(&m_rect) - m_rect.x; //We need 'left' more pixels on the left - - snprintf(vbuffer, 10, "%*g", precision, self->start); - PCF_FontGetSizeRequestRect(font, vbuffer, false, &m_rect); - right = SDLExt_RectLastX(&m_rect) - SDLExt_RectMidX(&m_rect);//We need 'right' more pixels on the right - } - - if(markings_location == Top){ - top = TEXT_SPACE + glyph_height; - }else if (markings_location == Bottom){ - bottom = TEXT_SPACE + glyph_height; - }else{ - printf("Unsupported Etching location for Horizontal orientation\n"); - return false; - } - }else if(self->orientation == RulerVertical){ - if(self->direction == RulerGrowAlongAxis){ - snprintf(vbuffer, 10, "%*g", precision, self->start); - PCF_FontGetSizeRequestRect(font, vbuffer, false, &m_rect); - top = SDLExt_RectMidY(&m_rect) - m_rect.y; - - snprintf(vbuffer, 10, "%*g", precision, self->end); - PCF_FontGetSizeRequestRect(font, vbuffer, false, &m_rect); - bottom = SDLExt_RectLastY(&m_rect) - SDLExt_RectMidY(&m_rect); - }else{ - snprintf(vbuffer, 10, "%*g", precision, self->start); - PCF_FontGetSizeRequestRect(font, vbuffer, false, &m_rect); - bottom = SDLExt_RectLastY(&m_rect) - SDLExt_RectMidY(&m_rect); - - snprintf(vbuffer, 10, "%*g", precision, self->end); - PCF_FontGetSizeRequestRect(font, vbuffer, false, &m_rect); - top = SDLExt_RectMidY(&m_rect) - m_rect.y; - } - - /* Assumes that self->end > self->start - * means that it's also the lenghtiest to - * write. It also just happens that we've - * just measured it's size in m_rect. - * */ - if(markings_location == Left){ - left = m_rect.w + TEXT_SPACE; - }else if (markings_location == Right) { - right = m_rect.w + TEXT_SPACE; - }else{ - printf("Unsupported Etching location for Vertical orientation\n"); - return false; - } - }else{ - printf("Unsupported orientation\n"); - return false; - } - -// printf("Width was %d, it's now %d\n", , fbw + left + right); - *w = fbw + left + right; - *h = fbh + top + bottom; - printf("Passed-in fbw: %d, returning w: %d\n",fbw, *w); - printf("ruler_area.w was: %d is now: %d\n",self->ruler_area.w, fbw); - - self->ruler_area = (SDL_Rect){ - .x = left, - .y = top, - /* Pretty useless, this is just - * re-setting to the same value - * as fbw/fbh has been set from - * these.*/ - .w = fbw, - .h = fbh - }; - printf("Final gauge area:\n"); - SDLExt_RectDump(&self->ruler_area); - printf("\n"); - return true; -} -#if __GNUC__ >= 8 -#pragma GCC diagnostic pop -#endif - -int generic_ruler_get_pixel_increment_for(GenericRuler *self, float value) -{ - if(value == -INFINITY) return 0; - if(value == INFINITY) - value = self->end; - - if(fmod(value, self->hatch_step) == 0){ /*Value is a big graduation*/ -// value = fmod(value, fabs(round(self->end - self->start)) + 1); - int ngrads = value/self->hatch_step - (self->start/self->hatch_step); - return ngrads * self->ppv * self->hatch_step; - }else{ - if(self->orientation == RulerHorizontal) - return (value - self->start)*((self->ruler_area.w-1) - 0)/(self->end - self->start) + 0; - else if(self->orientation == RulerVertical) - return (value - self->start)*((self->ruler_area.h-1) - 0)/(self->end - self->start) + 0; - else - printf("Unsupported orientation\n"); - } - return -1; -} - -/** - * @brief Draw the give color zones on the ruler - * - * If you want to have a spine line and/or hatch marks on top of said zones - * you have to draw the zones first, and other etches on top of that. - * - * @param self a GenericRuler - * @param spine_location Location of the spine line of the ruler. Even if you - * don't etch lines on the ruler at all, this function needs to know from where - * to start filling the ruler with color, especially if @p fill_ratio is not - * 1.0. The filling will start on the given location and grow to the opposite - * e.g. Left->Right, Bottom->Top, etc. The center location will grow as evenly - * as possible towards both opposite sides. - * @param nzones Number of zones in the @p zones array - * @param zones Address to the first of @p nzones zones. If overlapping, the - * last drawn zone will take precedence. - * @param fill_ratio amount of the ruler to fill with colors, from 0 (0%) - * to 1.0 (100%). - * @return true on success, false otherwise. - * - * TODO: When areas overlap, make them stack on top of - * one another, equally sharing the fill_ratio space. - */ -bool generic_ruler_draw_zones(GenericRuler *self, Location spine_location, int nzones, ColorZone *zones, float fill_ratio) -{ - int begin, end; - - int start_y,end_y; - int start_x, end_x; - int npixels; - - if(self->orientation == RulerHorizontal){ - /* number of px *to add* and thus can't be self->ruler_area.h - * which would go overboard as the area goes from area.x to - * area.x + (area.h-1) - */ - npixels = (self->ruler_area.h - 1)*fill_ratio; - if(spine_location == Top){ - start_y = self->ruler_area.y; - end_y = self->ruler_area.y + npixels; - }else if(spine_location == Center){ - start_y = SDLExt_RectMidY(&self->ruler_area) - (SDLExt_RectMidY(&self->ruler_area)-self->ruler_area.y)*fill_ratio; - end_y = SDLExt_RectMidY(&self->ruler_area) + (SDLExt_RectLastY(&self->ruler_area)-SDLExt_RectMidY(&self->ruler_area))*fill_ratio; - }else if (spine_location == Bottom) { - start_y = SDLExt_RectLastY(&self->ruler_area) - npixels; - end_y = SDLExt_RectLastY(&self->ruler_area); - }else{ - printf("Unsupported line position for Horizontal orientation"); - return false; - } - }else if(self->orientation == RulerVertical){ - npixels = (self->ruler_area.w - 1)*fill_ratio; - if(spine_location == Left){ - start_x = self->ruler_area.x; - end_x = self->ruler_area.x + npixels; - }else if(spine_location == Center){ - start_x = SDLExt_RectMidX(&self->ruler_area) - (SDLExt_RectMidX(&self->ruler_area)-self->ruler_area.x)*fill_ratio; - end_x = SDLExt_RectMidX(&self->ruler_area) + (SDLExt_RectLastX(&self->ruler_area)-SDLExt_RectMidX(&self->ruler_area))*fill_ratio; - }else if(spine_location == Right){ - start_x = SDLExt_RectLastX(&self->ruler_area) - npixels; - end_x = SDLExt_RectLastX(&self->ruler_area); - }else{ - printf("Unsupported line position for Vertical orientation"); - return false; - } - }else{ - printf("Unsupported gauge orientation"); - return false; - } - - /* Colored areas, if any are assumed to be sorted - * */ - SDL_LockSurface(GENERIC_LAYER(self)->canvas); - Uint32 *pixels = GENERIC_LAYER(self)->canvas->pixels; - for(int i = 0; i < nzones; i++){ - begin = generic_ruler_get_pixel_increment_for(self, zones[i].from); - end = generic_ruler_get_pixel_increment_for(self, zones[i].to); - /* begin/end are the pixels that represent the from/to area bound values - * if they are excluded, just go one pixel after/before.*/ - if(zones[i].flags & FromExcluded) - begin += 1; - if(zones[i].flags & ToExcluded) - end -= 1; - Uint32 bcolor = SDL_MapRGBA(GENERIC_LAYER(self)->canvas->format, - zones[i].color.r, - zones[i].color.g, - zones[i].color.b, - zones[i].color.a - ); - if(self->orientation == RulerHorizontal){ - for(int y = start_y; y <= end_y; y++){ - if(self->direction == RulerGrowAlongAxis){ - for(int x = self->ruler_area.x + begin; x <= self->ruler_area.x + end; x++){ - pixels[y * GENERIC_LAYER(self)->canvas->w + x] = bcolor; - } - }else{ - for(int x = SDLExt_RectLastX(&self->ruler_area) - end; x <= SDLExt_RectLastX(&self->ruler_area) - begin; x++){ - pixels[y * GENERIC_LAYER(self)->canvas->w + x] = bcolor; - } - } - } - }else if(self->orientation == RulerVertical){ - if(self->direction == RulerGrowAlongAxis){ - for(int y = self->ruler_area.y + begin; y <= self->ruler_area.y + end; y++){ - for(int x = start_x; x <= end_x; x++){ - pixels[y * GENERIC_LAYER(self)->canvas->w + x] = bcolor; - } - } - }else{ - for(int y = SDLExt_RectLastY(&self->ruler_area) - end; y <= SDLExt_RectLastY(&self->ruler_area) - begin; y++){ - for(int x = start_x; x <= end_x; x++){ - pixels[y * GENERIC_LAYER(self)->canvas->w + x] = bcolor; - } - } - } - } - } - SDL_UnlockSurface(GENERIC_LAYER(self)->canvas); - return true; -} - -/** - * @brief Write ruler hatches(lines) on the underlying canvas. - * - * @param self a GenericRuler - * @param color The color to use for hatches, in the underlying surface format - * @param etch_spine Whether (true/false) to draw the ruler's spine i.e. main - * line or not. - * @param etch_hatches Whether (true/false) to draw hatches i.e. unit lines - * perpendicular to the spine or not. - * @param spine_location Where to draw the spine. Valid locations for - * Horizontal gauges are Top,Center,Bottom and Left, Center, Right for Vertical - * gauges. Ignored when @p spine is false. - * @return true on success, false otherwise. - * - * - */ -bool generic_ruler_etch_hatches(GenericRuler *self, Uint32 color, bool etch_spine, bool etch_hatches, Location spine_location) -{ - Uint32 *pixels; - int pcursor; /*Pixel index cursor*/ - int increment; - - generic_layer_lock(GENERIC_LAYER(self)); - pixels = GENERIC_LAYER(self)->canvas->pixels; - if(self->orientation == RulerHorizontal){ - /*Spine (main line)*/ - if(etch_spine){ - int y = -1; - if(spine_location == Center) - y = SDLExt_RectMidY(&self->ruler_area); - else if(spine_location == Bottom) - y = SDLExt_RectLastY(&self->ruler_area); - else if(spine_location == Top) - y = self->ruler_area.y; - else - printf("Unsupported line position for Horizontal orientation\n"); - if(y < 0) - return false; //TODO:Unlock pixels - for(int x = self->ruler_area.x; x <= SDLExt_RectLastX(&self->ruler_area); x++) - pixels[y * GENERIC_LAYER(self)->canvas->w + x] = color; - } - /*Hatch marks*/ - if(etch_hatches){ - for(float i = self->start; i <= self->end; i += self->hatch_step){ - increment = generic_ruler_get_pixel_increment_for(self, i); - pcursor = (self->direction == RulerGrowAlongAxis) - ? self->ruler_area.x + increment - : SDLExt_RectLastX(&self->ruler_area) - increment; - printf("Etching value %d at x=%d (increment was %d)\n", (int)i, pcursor, increment); - for(int y = self->ruler_area.y; y <= SDLExt_RectLastY(&self->ruler_area); y++) - pixels[y * GENERIC_LAYER(self)->canvas->w + pcursor] = color; - } - } - }else if(self->orientation == RulerVertical) { - /*Spine (main line)*/ - if(etch_spine){ - int x = -1; - if(spine_location == Center) - x = SDLExt_RectMidX(&self->ruler_area); - else if(spine_location == Left) - x = self->ruler_area.x; - else if(spine_location == Right) - x = SDLExt_RectLastX(&self->ruler_area); - else - printf("Unsupported line position for Vertical orientation\n"); - if(x < 0) - return false; //TODO:Unlock pixels - for(int y = self->ruler_area.y; y <= SDLExt_RectLastY(&self->ruler_area); y++) - pixels[y * GENERIC_LAYER(self)->canvas->w + x] = color; - } - /*Hatch marks*/ - if(etch_hatches){ - for(float i = self->start; i <= self->end; i += self->hatch_step){ - increment = generic_ruler_get_pixel_increment_for(self, i); - pcursor = (self->direction == RulerGrowAlongAxis) - ? self->ruler_area.y + increment - : SDLExt_RectLastY(&self->ruler_area) - increment; - printf("Drawing %f hatch at y = %d\n",i, pcursor); - for(int x = self->ruler_area.x; x < self->ruler_area.x + self->ruler_area.w; x++){ - pixels[pcursor * GENERIC_LAYER(self)->canvas->w + x] = color; - } - } - } - }else{ - printf("Unsupported orientation\n"); - return false; //TODO:Unlock pixels - } - generic_layer_unlock(GENERIC_LAYER(self)); - return true; -} - -/** - * @brief Etch markings (numbers) on the ruler at the predefined - * step - * - * @param self a GenericRuler - * @param location Where to put the markings. Valid locations for Horizontal - * rulers are: Top, Bottom while valid locations for Vertical gauges are - * Left and Right. - * @param font The PCF_Font to use. Must be the same used when calling - * generic_ruler_get_size_request - * @param color The color to use, in the underlying surface format - * @return true on success, false otherwise. - * - * @see generic_ruler_get_size_request - */ -/*TODO: Handle values ndigits vs precision ints vs floats*/ -bool generic_ruler_etch_markings(GenericRuler *self, Location markings_location, PCF_Font *font, Uint32 color, int8_t precision) -{ - int pcursor; /*Pixel cursor*/ - int increment; - - if(self->orientation == RulerHorizontal){ - for(float i = self->start; i <= self->end; i += self->hatch_step){ - increment = generic_ruler_get_pixel_increment_for(self, i); - pcursor = (self->direction == RulerGrowAlongAxis) - ? self->ruler_area.x + increment - : SDLExt_RectLastX(&self->ruler_area) - increment; - if(markings_location == Bottom) - PCF_FontWriteNumberAt(font, - &i, TypeFloat, precision, - color, false, - GENERIC_LAYER(self)->canvas, pcursor, - self->ruler_area.h + TEXT_SPACE, - CenterOnCol | BelowRow - ); - else if(markings_location == Top) - PCF_FontWriteNumberAt(font, - &i, TypeFloat, precision, - color, false, - GENERIC_LAYER(self)->canvas, pcursor, - self->ruler_area.y - TEXT_SPACE, - CenterOnCol | AboveRow - ); - else{ - printf("Unsupported etch position for horizontal scale\n"); - return false; - } - } - }else if(self->orientation == RulerVertical){ - for(float i = self->start; i <= self->end; i += self->hatch_step){ - increment = generic_ruler_get_pixel_increment_for(self, i); - printf("increment for %f is %d\n",i, increment); - pcursor = (self->direction == RulerGrowAlongAxis) - ? self->ruler_area.y + increment - : SDLExt_RectLastY(&self->ruler_area) - increment; - if(markings_location == Right) - PCF_FontWriteNumberAt(font, - &i, TypeFloat, precision, - color, false, - GENERIC_LAYER(self)->canvas, - self->ruler_area.w + TEXT_SPACE, - pcursor, - RightToCol | CenterOnRow - ); - else if(markings_location == Left) - PCF_FontWriteNumberAt(font, - &i, TypeFloat, precision, - color, false, - GENERIC_LAYER(self)->canvas, - self->ruler_area.x - TEXT_SPACE, - pcursor, - LeftToCol | CenterOnRow - ); - else{ - printf("Unsupported etch position for vertical scale\n"); - return false; - } - } - }else{ - printf("Unsupported orientation\n"); - return false; - } - return true; -} - -void generic_ruler_clip_value(GenericRuler *self, float *value) -{ - if(*value > self->end) - *value = self->end; - if(*value < self->start) - *value = self->start; -} diff --git a/generic-ruler.h b/generic-ruler.h deleted file mode 100644 index 20dfcf7..0000000 --- a/generic-ruler.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef GENERIC_RULER_H -#define GENERIC_RULER_H - -#include "generic-layer.h" - -#include "SDL_pcf.h" - -typedef enum __attribute__ ((__packed__)){ - RulerVertical, - RulerHorizontal, - NRulerOrientations -}RulerOrientation; - -typedef enum __attribute__ ((__packed__)){ - RulerGrowAlongAxis = 0, /*Grows left to right, top to bottom*/ - RulerGrowAgainstAxis = 1, /*Values grow in reverse with respect to the axis*/ -}RulerDirection; - -typedef enum __attribute__ ((__packed__)){ - LocationNone = 0, - Top, - Center, - Bottom, - Left, - Right, - NLocations -}Location; - -/*TODO: Use only 2 bits*/ -typedef enum __attribute__ ((__packed__)){ - FromIncluded = 1 << 0, /*00000001*/ - FromExcluded = 1 << 1, /*00000010*/ - ToIncluded = 1 << 2, /*00000100*/ - ToExcluded = 1 << 3 /*00001000*/ -}BoundFlags; - -typedef struct{ - float from; - float to; - BoundFlags flags; - SDL_Color color; -}ColorZone; - - -/** - * (Really) Generic mapping between a range of values {@value #start}, {@value #start} - * and an image. - */ -typedef struct{ - GenericLayer super; - - RulerOrientation orientation; - RulerDirection direction; - SDL_Rect ruler_area; /*ruler area*/ - float start; /*first (included) value in the range*/ - float end; /*last (included) value in the range*/ - float hatch_step; /*Spacing between hatch marks. TODO: arbitrary number of hatch levels/levels*/ - - float ppv; /*scale, in pixels per value*/ -}GenericRuler; - -GenericRuler *generic_ruler_init(GenericRuler *self, - RulerOrientation orientation, - RulerDirection direction, - float start, float end, float step, - PCF_Font *markings_font, - Location markings_location, - int8_t markings_precision, - int ruler_w, int ruler_h); - -void generic_ruler_dispose(GenericRuler *self); - -bool generic_ruler_draw_zones(GenericRuler *self, Location spine_location, int nzones, ColorZone *zones, float fill_ratio); -bool generic_ruler_etch_hatches(GenericRuler *self, Uint32 color, bool etch_spine, bool etch_hatches, Location spine_location); -bool generic_ruler_etch_markings(GenericRuler *self, Location markings_location, PCF_Font *font, Uint32 color, int8_t precision); - -int generic_ruler_get_pixel_increment_for(GenericRuler *self, float value); -void generic_ruler_clip_value(GenericRuler *self, float *value); -#endif /* GENERIC_RULER_H */ diff --git a/http-buffer.c b/http-buffer.c deleted file mode 100644 index 5603b11..0000000 --- a/http-buffer.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -//#include -#include -#include -#include - -#include "http-buffer.h" - -HttpBuffer *http_buffer_new(size_t len) -{ - HttpBuffer *self; - - self = calloc(1, sizeof(HttpBuffer)); - if(self){ - if(len){ - self->buffer = malloc(sizeof(char) * len); - if(!self->buffer){ - free(self); - return(NULL); - } - self->allocated = len; - } - } - return(self); -} - -/** - * @brief Ensure that @param self have enough rooom to store @param size bytes - * - * - */ -bool http_buffer_resize(HttpBuffer *self, size_t size) -{ - if(self->allocated < size){ - void *tmp = realloc(self->buffer, size); - if(!tmp) return false; - self->buffer = tmp; - self->allocated = size; - } - return true; -} - -/** - * @brief Puts @param content into @param self, ensuring @param self is - * NULL-terminated - * - */ -bool http_buffer_set_content(HttpBuffer *self, const void *content, size_t len) -{ - bool rv; - - rv = http_buffer_resize(self, len+1); /*TODO: Handle overflow*/ - if(!rv) return 0; - - memcpy(self->buffer, content, len); - self->buffer[len] = '\0'; - self->len = len; - - return true; -} - -/** - * @brief Puts @param content into @param self, ensuring @param self is - * NULL-terminated - * - */ -bool http_buffer_add_content(HttpBuffer *self, const void *content, size_t len) -{ - bool rv; - - rv = http_buffer_resize(self, self->allocated+len+1); /*TODO: Handle overflow*/ - if(!rv) return 0; - - memcpy(self->buffer+self->len, content, len); - self->len += len; - self->buffer[self->len] = '\0'; - - return true; -} diff --git a/http-buffer.h b/http-buffer.h deleted file mode 100644 index 6717902..0000000 --- a/http-buffer.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef HTTP_BUFFER_H -#define HTTP_BUFFER_H -#include -#include - -typedef struct{ - char *buffer; - size_t allocated; - size_t len; -}HttpBuffer; - -HttpBuffer *http_buffer_new(size_t len); -bool http_buffer_resize(HttpBuffer *self, size_t size); - -bool http_buffer_set_content(HttpBuffer *self, const void *content, size_t len); -bool http_buffer_add_content(HttpBuffer *self, const void *content, size_t len); -#endif /* HTTP_BUFFER_H */ diff --git a/http-download.c b/http-download.c deleted file mode 100644 index 2d62693..0000000 --- a/http-download.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include -#include -#include - -#include - -#include "misc.h" - -bool http_download_file(char *url, char *output) -{ - CURL *curl; - FILE *fp; - CURLcode res; - bool ret; - - ret = create_path(output); - if(!ret) return false; - -// printf("Query: %s\n",url); - curl = curl_easy_init(); - if(!curl) return false; - - fp = fopen(output,"wb"); - if(!fp){ - printf("Couldn't open %s for writting\n",output); - return false; - } - curl_easy_setopt(curl, CURLOPT_URL, url); - curl_easy_setopt(curl, - CURLOPT_USERAGENT, "curl/7.68.0" - ); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); - curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); - - printf("Downloading %s, please wait\t", url); - fflush(stdout); - res = curl_easy_perform(curl); - /* always cleanup */ - curl_easy_cleanup(curl); - fclose(fp); - if(res != CURLE_OK){ - unlink(output); - printf("[ %sFAILED%s ]\n", - "\033[0;31m", /*red*/ - "\033[0m" /*Reset*/ - ); - return false; - } - - printf("[ %sOK%s ]\n", - "\033[0;32m", /*red*/ - "\033[0m" /*Reset*/ - ); - return true; -} - - diff --git a/http-download.h b/http-download.h deleted file mode 100644 index faf2e78..0000000 --- a/http-download.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef HTTP_DOWNLOAD_H -#define HTTP_DOWNLOAD_H -#include - -bool http_download_file(char *url, char *output); - -#endif /* HTTP_DOWNLOAD_H */ diff --git a/http-request.c b/http-request.c deleted file mode 100644 index 857476d..0000000 --- a/http-request.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include -#include - -#include - -#include "http-buffer.h" - - -static size_t handle_response(void *contents, size_t size, - size_t nmemb, HttpBuffer *buffer) -{ - bool rv; - size_t len; - - len = size * nmemb; - rv = http_buffer_add_content(buffer, contents, len); - - return rv ? len : 0; -} - -bool http_request(const char *url, HttpBuffer **buffer) -{ - CURL *curl; - CURLcode res; - bool ret; - - *buffer = (*buffer) ? (*buffer) : http_buffer_new(0); - if(!(*buffer)) return false; - -// printf("Query: %s\n",url); - curl = curl_easy_init(); - if(!curl) return false; - - curl_easy_setopt(curl, CURLOPT_URL, url); - curl_easy_setopt(curl, - CURLOPT_USERAGENT, "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) " - "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36" - ); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, handle_response); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)(*buffer)); - curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); - - res = curl_easy_perform(curl); - /* always cleanup */ - curl_easy_cleanup(curl); - if(res != CURLE_OK){ - return false; - } - - return true; -} - - diff --git a/http-request.h b/http-request.h deleted file mode 100644 index 775d007..0000000 --- a/http-request.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef HTTP_REQUEST_H -#define HTTP_REQUEST_H -#include -#include "http-buffer.h" - -bool http_request(const char *url, HttpBuffer **buffer); -#endif /* HTTP_REQUEST_H */ diff --git a/ladder-gauge.c b/ladder-gauge.c deleted file mode 100644 index 49c1f49..0000000 --- a/ladder-gauge.c +++ /dev/null @@ -1,255 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include - -#include "ladder-gauge.h" -#include "generic-layer.h" -#include "sdl-colors.h" -#include "misc.h" - -static void ladder_gauge_update_state(LadderGauge *self, Uint32 dt); -static void ladder_gauge_render(LadderGauge *self, Uint32 dt, RenderContext *ctx); -static void *ladder_gauge_dispose(LadderGauge *self); -static BaseGaugeOps ladder_gauge_ops = { - .render = (RenderFunc)ladder_gauge_render, - .update_state = (StateUpdateFunc)ladder_gauge_update_state, - .dispose = (DisposeFunc)ladder_gauge_dispose -}; - - -LadderGauge *ladder_gauge_new(int w, int h, LadderPageDescriptor *descriptor, int rubis) -{ - LadderGauge *self; - - self = calloc(1, sizeof(LadderGauge)); - if(self){ - if(!ladder_gauge_init(self, w, h, descriptor, rubis)){ - return base_gauge_free(BASE_GAUGE(self)); - } - } - return self; -} - -LadderGauge *ladder_gauge_init(LadderGauge *self, int w, int h, LadderPageDescriptor *descriptor, int rubis) -{ - base_gauge_init(BASE_GAUGE(self), &ladder_gauge_ops, w, h); - - self->descriptor = descriptor; - if(rubis > 0) - self->rubis = rubis; - else - self->rubis = round(base_gauge_h(BASE_GAUGE(self))/2.0); - return self; -} - -static void *ladder_gauge_dispose(LadderGauge *self) -{ - for(int i = 0; i < N_PAGES; i++){ - if(self->pages[i]){ - ladder_page_free(self->pages[i]); - self->pages[i] = NULL; - } - } - if(self->descriptor) - free(self->descriptor); /*No need for virtual dispose ATM*/ - - return self; -} - -bool ladder_gauge_set_value(LadderGauge *self, float value, bool animated) -{ - return sfv_gauge_set_value(SFV_GAUGE(self), value, animated); -} - -/** - * - * @param idx: the page number, computed from page range. - * If range is 0-699, then page 0 would be 0 -> 699, page 1 - * 700-1399, etc. - */ -LadderPage *ladder_gauge_get_page(LadderGauge *self, uintf8_t idx) -{ - int a_idx; - uintf8_t cmp; /*current max page*/ - uintf8_t offset; /*Number of pages to move (advance of back up)*/ - int j; - - cmp = self->base + (N_PAGES-1); - if(idx > cmp){ - offset = idx - cmp; - for(int i = 0; i < N_PAGES; i++){ - j = i - offset; -// printf("j = %d - %d = %d\n",i,offset,j); - if( j < 0 ){ - if(self->pages[i]){ - ladder_page_free(self->pages[i]); - self->pages[i] = NULL; - } - }else{ - self->pages[j] = self->pages[i]; - self->pages[i] = NULL; - } - } - self->base += offset; - }else if(idx < self->base){ - offset = self->base - idx; - for(int i = N_PAGES-1; i >= 0; i--){ - j = i + offset; - if( j > N_PAGES-1){ - if(self->pages[i]){ - ladder_page_free(self->pages[i]); - self->pages[i] = NULL; - } - }else{ - self->pages[j] = self->pages[i]; - self->pages[i] = NULL; - } - } - self->base -= offset; - } - - a_idx = idx - self->base; - if(!self->pages[a_idx]) - self->pages[a_idx] = ladder_page_descriptor_create_page(self->descriptor, idx); - - return self->pages[a_idx]; -} - -LadderPage *ladder_gauge_get_page_for(LadderGauge *self, float value) -{ - int page_idx; - - page_idx = (int)value/(self->descriptor->page_size); - - return ladder_gauge_get_page(self, page_idx); -} - -static void ladder_gauge_update_state(LadderGauge *self, Uint32 dt) -{ - float y; - float rubis; - LadderPage *page, *page2; - SDL_Rect dst_region = {0,0,base_gauge_w(BASE_GAUGE(self)),base_gauge_h(BASE_GAUGE(self))}; - - memset(&self->state, 0, sizeof(LadderGaugeState)); - - SFV_GAUGE(self)->value = SFV_GAUGE(self)->value >= 0 ? SFV_GAUGE(self)->value : 0.0f; - - page = ladder_gauge_get_page_for(self, SFV_GAUGE(self)->value); - - y = ladder_page_resolve_value(page, SFV_GAUGE(self)->value); -// printf("y = %f for value = %f\n",y,value); - rubis = (self->rubis < 0) ? base_gauge_h(BASE_GAUGE(self)) / 2.0 : self->rubis; - SDL_Rect portion = { - .x = 0, - .y = round(y - rubis), - .w = generic_layer_w(GENERIC_LAYER(page)), - .h = base_gauge_h(BASE_GAUGE(self)) - }; - /* Ensures that portion.y + portion.h doesn't got past image bounds: - * w/h are ignored by SDL_BlitSurface, but when using SDL_Renderers wrong - * values will stretch the image. - * */ - if(portion.y + portion.h > generic_layer_h(GENERIC_LAYER(page))) - portion.h = generic_layer_h(GENERIC_LAYER(page)) - portion.y; - /*All pages must have the same size*/ - if(portion.y < 0){ //Fill top - SDL_Rect patch = { - .x = 0, - .y = generic_layer_h(GENERIC_LAYER(page)) + portion.y, //means - portion.y as portion.y < 0 here - .w = generic_layer_w(GENERIC_LAYER(page)), - .h = generic_layer_h(GENERIC_LAYER(page)) - patch.y - }; - if(self->descriptor->direction == TOP_DOWN){ - /* 0 is on top, 100 is downwards. We need to fill the top with values before the begining - * of the current page, i.e get the previous page */ - int pidx = ladder_page_get_index(page); - if(pidx > 0){ - page2 = ladder_gauge_get_page(self, pidx - 1); - self->state.patches[self->state.npatches].layer = GENERIC_LAYER(page2); - self->state.patches[self->state.npatches].src = patch; - self->state.patches[self->state.npatches].dst = dst_region; - self->state.patches[self->state.npatches].dst.h = patch.h; - self->state.npatches++; - } - }else{ - /* 0 at the bottom, 100 is upwards. We need to fill the top with values after the end - * of the current page, i.e get the next page */ - int pidx = ladder_page_get_index(page); - page2 = ladder_gauge_get_page(self, pidx + 1); - self->state.patches[self->state.npatches].layer = GENERIC_LAYER(page2); - self->state.patches[self->state.npatches].src = patch; - self->state.patches[self->state.npatches].dst = dst_region; - self->state.patches[self->state.npatches].dst.h = patch.h; - self->state.npatches++; - } - dst_region.y = patch.h; - dst_region.h -= patch.h; - portion.y = 0; - portion.h -= patch.h; - } - self->state.patches[self->state.npatches].layer = GENERIC_LAYER(page); - self->state.patches[self->state.npatches].src = portion; - self->state.patches[self->state.npatches].src.h = MIN(portion.h, generic_layer_h(GENERIC_LAYER(page))); - self->state.patches[self->state.npatches].dst = dst_region; - self->state.patches[self->state.npatches].dst.h = MIN(portion.h, generic_layer_h(GENERIC_LAYER(page))); - self->state.npatches++; - - dst_region.y += portion.h; - dst_region.h -= portion.h; - - if(dst_region.h > 0){// fill bottom - SDL_Rect patch = { - .x = 0, - .y = 0, - .w = generic_layer_w(GENERIC_LAYER(page)), - .h = MIN(dst_region.h, generic_layer_h(GENERIC_LAYER(page))) - }; - if(self->descriptor->direction == TOP_DOWN){ - /* 0 is on top, 100 is downwards. We need to fill the bottom with values that are after the end - * of the current page, i.e get the next page */ - int pidx = ladder_page_get_index(page); - page2 = ladder_gauge_get_page(self, pidx + 1); - self->state.patches[self->state.npatches].layer = GENERIC_LAYER(page2); - self->state.patches[self->state.npatches].src = patch; - self->state.patches[self->state.npatches].dst = dst_region; - self->state.patches[self->state.npatches].dst.h = patch.h; - self->state.npatches++; - }else{ - /* 0 at the bottom, 100 is upwards. We need to fill the bottom with values that are before the begining - * of the current page, i.e get the previous page */ - int pidx = ladder_page_get_index(page); - if(pidx > 0){ - page2 = ladder_gauge_get_page(self, pidx - 1); - self->state.patches[self->state.npatches].layer = GENERIC_LAYER(page2); - self->state.patches[self->state.npatches].src = patch; - self->state.patches[self->state.npatches].dst = dst_region; - self->state.patches[self->state.npatches].dst.h = patch.h; - self->state.npatches++; - } - } - } - self->state.pskip = round(base_gauge_w(BASE_GAUGE(self))/2.0); -} - -static void ladder_gauge_render(LadderGauge *self, Uint32 dt, RenderContext *ctx) -{ - for(int i = 0; i < self->state.npatches; i++){ - base_gauge_blit_layer(BASE_GAUGE(self), ctx, - self->state.patches[i].layer, - &self->state.patches[i].src, - &self->state.patches[i].dst - ); - } - base_gauge_draw_rubis(BASE_GAUGE(self), - ctx, self->rubis, - &SDL_RED, self->state.pskip - ); - base_gauge_draw_outline(BASE_GAUGE(self), ctx, &SDL_WHITE, NULL); -} diff --git a/ladder-gauge.h b/ladder-gauge.h deleted file mode 100644 index b9c52c4..0000000 --- a/ladder-gauge.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef LADDER_GAUGE_H -#define LADDER_GAUGE_H -#include - -#include "sfv-gauge.h" -#include "ladder-page.h" -#include "misc.h" - -#define N_PAGES 4 - -typedef struct{ - GenericLayer *layer; - SDL_Rect src; - SDL_Rect dst; -}LadderPagePatch; - -typedef struct{ - LadderPagePatch patches[3]; /*Up to 3: top, middle, bottom*/ - uintf8_t npatches; - - int pskip; -}LadderGaugeState; - - -typedef struct{ - SfvGauge super; - - int rubis; - - LadderPage *pages[N_PAGES]; - uintf8_t base; - - LadderPageDescriptor *descriptor; - - LadderGaugeState state; -}LadderGauge; - - -LadderGauge *ladder_gauge_new(int w, int h, LadderPageDescriptor *descriptor, int rubis); -LadderGauge *ladder_gauge_init(LadderGauge *self, int w, int h, LadderPageDescriptor *descriptor, int rubis); - -bool ladder_gauge_set_value(LadderGauge *self, float value, bool animated); -#endif /* LADDER_GAUGE_H */ diff --git a/ladder-page.c b/ladder-page.c deleted file mode 100644 index bd70b76..0000000 --- a/ladder-page.c +++ /dev/null @@ -1,276 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include -#include -#include - -#include "generic-layer.h" -#include "ladder-page.h" -#include "sdl-colors.h" -#include "SDL_pcf.h" - - -LadderPageDescriptor *ladder_page_descriptor_init(LadderPageDescriptor *self, int width, int height, - ScrollType direction, float page_size, float vstep, - float vsubstep, LPInitFunc func) -{ - self->width = width; - self->height = height; - self->direction = direction; - self->page_size = page_size; - self->vstep = vstep; - self->vsubstep = vsubstep; - self->offset = NAN; - self->init_page = func; - - return self; -} - -/*TODO: Check if ppv could be intergrated into the descriptor*/ -void ladder_page_descriptor_compute_offset(LadderPageDescriptor *self, float ppv) -{ - float half_split; - int leading, trailing; - float pixel_increment; - - pixel_increment = ppv * self->vstep; /*How many pixels between two ruler marks*/ - - half_split = (pixel_increment-1)/2.0; - - if(self->direction == TOP_DOWN){ /*0 is at the top of the image, increments downwards*/ - leading = ceil(half_split); - self->offset = -1.0 * leading*ppv; - }else{ /*0 is at the bottom of the image, increments upwards*/ - trailing = floor(half_split); - self->offset = -1.0 * trailing/ppv; - } -} - -LadderPage *ladder_page_descriptor_create_page(LadderPageDescriptor *self, int index) -{ - LadderPage *rv; - float start; - - start = index * self->page_size; /*'nominal' start, will be offsted by the init func */ - - rv = ladder_page_new(start, self); - - return self->init_page(rv); -} - -LadderPage *ladder_page_new(float start, LadderPageDescriptor *descriptor) -{ - LadderPage *self; - - self = calloc(1, sizeof(LadderPage)); - if(self){ - VERTICAL_STRIP(self)->start = start; - VERTICAL_STRIP(self)->end = NAN; - self->descriptor = descriptor; - } - return self; -} - - -LadderPage *ladder_page_init(LadderPage *self) -{ - VerticalStrip *strip; - GenericLayer *layer; - LadderPageDescriptor *descriptor; - - strip = VERTICAL_STRIP(self); - layer = GENERIC_LAYER(self); - descriptor = LADDER_PAGE(self)->descriptor; - - bool rv; - - - rv = generic_layer_init(GENERIC_LAYER(self), descriptor->width, descriptor->height); - if(!rv){ - return NULL; - } - - strip->ppv = generic_layer_h(layer)/(descriptor->page_size*1.0); -// printf("LadderPageDescriptor ppv is %f\n",strip->ppv); -// printf("Page marking range is [%f, %f]\n", strip->start, strip->end); - - /* We are just going to offset the interval, size remains the same - * so ppv wont change and can be computed before or afterwards*/ - if(isnan(descriptor->offset)){ - ladder_page_descriptor_compute_offset(descriptor, strip->ppv); - } - - strip->start += descriptor->offset; - strip->end = strip->start + descriptor->page_size-1; - -// int page_index = ladder_page_get_index(LADDER_PAGE(self)); -// printf("Page %d real range is [%f, %f]\n",page_index, strip->start, strip->end); - - return self; -} - -void ladder_page_free(LadderPage *self) -{ - vertical_strip_dispose(VERTICAL_STRIP(self)); - free(self); -} - -int ladder_page_get_index(LadderPage *self) -{ - return ceil(VERTICAL_STRIP(self)->start/(self->descriptor->page_size)); -} - -float ladder_page_resolve_value(LadderPage *self, float value) -{ - VerticalStrip *strip; - bool reverse; - - strip = VERTICAL_STRIP(self); - reverse = (self->descriptor->direction == BOTTUM_UP); - - if(fmod(value, self->descriptor->vstep) == 0){ /*Value is a big graduation*/ - float y; - value = fmod(value, fabs(round(strip->end - strip->start)) + 1); - int ngrads = value/self->descriptor->vstep; - if(!reverse) - y = self->descriptor->fei + ngrads * strip->ppv * self->descriptor->vstep; - else - y = self->descriptor->fei - ngrads * strip->ppv * self->descriptor->vstep; - return y; - }else if(self->descriptor->vsubstep != 0 && fmod(value, self->descriptor->vsubstep) == 0){ /*Value is a small graduation*/ - float y; - value = fmod(value, fabs(round(strip->end - strip->start)) + 1); - int ngrads = value/self->descriptor->vsubstep; - if(!reverse) - y = self->descriptor->fei + ngrads * strip->ppv * self->descriptor->vsubstep; - else - y = self->descriptor->fei - ngrads * strip->ppv * self->descriptor->vsubstep; - return y; - }else{ - return vertical_strip_resolve_value(strip, value, reverse); - } -} - - -void ladder_page_draw_ruler(LadderPage *self, uint8_t base_unit_px, LadderPageRulerLocation location, - uint8_t small_step_width, uint8_t big_step_width) -{ - SDL_Surface *surface; - int x; - Uint32 white; - Uint32 *pixels; - int firstx, lastx; - int ticks_drawn; - - int n_steps; - int step_px; - - int preload_px; - int preload_ticks; - - int base_unit = self->descriptor->vsubstep; - int marking_step = self->descriptor->vstep; - - -// printf("Drawing ladder page ruler with base_unit: %d, base_unit_px: %d, marking_step: %d marking_step %% base_unit: %d\n", base_unit, base_unit_px, marking_step, marking_step % base_unit); - assert(marking_step % base_unit == 0); - - /* This is not how many *ticks* there are, but how much base units *increments/intervals* you must walk - * starting at a big tick to go to the next. - * */ - n_steps = marking_step/base_unit; - step_px = base_unit_px * n_steps; - - /* As pages will be stiched together, we start drawing pretending that we are in the middle of - * a "big tick" (which is step_px long) so we preload that amount of pixels. As we have assumed - * starting with the "bigger half" (see comments in ladder-page.h), we need to preload the - * "small half" has already written. - * - * We also preload the correct number of ticks within that range as if we'd drawn them, *plus* - * the starting big tick of that interval we are in the middle of so everything will line up. - */ - if(step_px % 2 == 0){ - preload_px = step_px/2; - }else{ - preload_px = floor(step_px/2.0); - } - preload_ticks = preload_px / base_unit_px + 1; -// printf("Preload pixels: %d, preload ticks: %d\n", preload_px, preload_ticks); - - surface = GENERIC_LAYER(self)->canvas; - white = SDL_UWHITE(surface); - - SDL_LockSurface(surface); - pixels = surface->pixels; - ticks_drawn = preload_ticks; - for(int y = surface->h-1, cnt = 1; y >= 0; y--, cnt++){ - lastx = location == LocationLeft ? 0 : (surface->w-1); - firstx = lastx; - if( (cnt + preload_px) % base_unit_px == 0){ /*tick mark*/ - if(ticks_drawn % n_steps == 0){ /*big tick mark*/ - if(location == LocationLeft) - lastx = firstx + big_step_width; - else - firstx = lastx - big_step_width; - }else{ /*small tick mark*/ - if(location == LocationLeft) - lastx = firstx + small_step_width; - else - firstx = lastx - small_step_width; - } - ticks_drawn++; - }else{ - firstx = lastx; - } - for(int j = firstx; j <= lastx; j++){ - Uint32 idx = y * surface->w + j; - pixels[idx] = white; - } - } - SDL_UnlockSurface(surface); -} - -/*Put markings*/ -void ladder_page_etch_markings(LadderPage *self, PCF_Font *font, uint halign, int offset) -{ - float y; - - VerticalStrip *strip; - GenericLayer *layer; - int page_index; - - assert((halign & HALIGN_RIGHT || halign & HALIGN_LEFT)); - - strip = VERTICAL_STRIP(self); - layer = GENERIC_LAYER(self); - - page_index = ladder_page_get_index(self); -// printf("Page %d real range is [%f, %f]\n",page_index, strip->start, strip->end); -// -// printf("Writing indexes on %d starting at %d to %f\n",page_index, page_index*self->descriptor->page_size, strip->end); - Uint32 white = SDL_UWHITE(layer->canvas); -// printf("Going from %zu to %f with step %f\n", page_index*self->descriptor->page_size, strip->end, self->descriptor->vstep); - for(int i = page_index*self->descriptor->page_size; i <= strip->end; i += self->descriptor->vstep){ - y = ladder_page_resolve_value(self, i); -// printf("Writing index %d at y = %f\n", i, y); - int x; - PCF_TextPlacement placement; - if(halign & HALIGN_RIGHT){ - x = (generic_layer_w(layer)-1) - offset; - placement = LeftToCol; - }else{ - x = offset; - placement = RightToCol; - } - PCF_FontWriteNumberAt(font, - &i, TypeInt, 0, - white, false, layer->canvas, - x, y, placement | CenterOnRow); - } -} diff --git a/ladder-page.h b/ladder-page.h deleted file mode 100644 index 31acb0c..0000000 --- a/ladder-page.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef LADDER_PAGE_H -#define LADDER_PAGE_H - -#include "SDL_pcf.h" -#include "vertical-strip.h" - -typedef struct _LadderPage LadderPage; - -typedef enum {TOP_DOWN, BOTTUM_UP} ScrollType; -typedef LadderPage *(*LPInitFunc) (LadderPage *self); - -typedef enum {LocationLeft, LocationRight} LadderPageRulerLocation; - -/** - * LadderPageDescriptor helps define how the inifinite - * strip is made out of pages, or how pages are put together - * into the infinite strip. - * - * The strip is defined by a page dimension {@value page_size} - * and a step between values {@value vstep} that tells the - * LadderGauge how many values are in a page. i.e The first page - * of a strip with a descriptor having a page of size of 70 with - * a step of 10 will likely go from 0 to 69 (70 values). The image - * is assumed to have marks every 10 values. - * - * The image must in fact be larger than that: 0 cannot be the very first - * pixel, and 69 cannot be the very last: This wouldn't allow for - * a) putting a number in front of the mark: The digit being centered on - * the mark, there wouldn't be enough space for the lower/upper part as - * the digit centerline would be right at 0 or max-1 - * b) chaining up the pages: the strip is built by concatenating pages - * one right after/before the other. Having the min/max marks right at - * 0/max pixels would result in eating up an interval: Imagine page 0 - * being *values* 0-9 and page 2 being *values* 10-19, with graduations - * every unit. It's safe to assume that the ruler image will have a fixed - * amount of pixels between each mark. - * A direct contactenation would have 9 and 10 with absolutely no interval - * in-between which doesn't work. - * Therefore the image needs to be larger than the interval. It needs to have - * a leading and trailing area that together account for the same space as in - * between two value. i.e if value are 6 pixels appart, you need 3 leading pixels - * and 3 trailing pixels. This will allow for seamless concatenatation. - * WARNING: If it's not possible to have an equal amount of leading/trailing pixels, - * LEADING area must get the HIGHER number of pixels. Example: 7 pixels spacing - * between values, hence 3.5 pixels which cannot be done. 4 leading pixels, 3 - * trailing. - * - * Either if you use a loaded image or generate it on the fly, you must follow this - * rule. - * - * The creation process will compute {@value offset} that will the be used to "move" - * pages from the "nominal" interval (Page X starts at V) to the real interval that - * includes the leading/trailing pixels (Page X has it's first mark at V but in fact - * has pixels that maps to V-offset) - * - */ -typedef struct{ - int width; /*page width in pixels*/ - int height; /*page height in pixels*/ - - ScrollType direction; - size_t page_size; /*number of values per page*/ - - float fei; /*First etch mark index*/ - float vstep; /*Main unit etch marks*/ - float vsubstep; /*Subunit unit etch marks*/ - - float offset; /*Trailing/leading pixels turned into value units*/ - - LPInitFunc init_page; -}LadderPageDescriptor; - - -/** - * Abstract struct that represent a VerticalStrip that will - * be used as a page in a LadderGauge. The LadderGauge displays - * a tape-like widget that scrolls an infinite slider. The - * 'infinite' slider is made out of pages. - * - * Each page represents a range. All pages making up an infinite - * slider share a common descriptor that helps understanding the - * page within the tape and create new ones. - * - * Each page can be linked to an index within the strip. Page X - * can be computed as started at value V. - * - */ -struct _LadderPage{ - VerticalStrip super; - -// const LadderPageDescriptor *descriptor; - LadderPageDescriptor *descriptor; -}; - -#define LADDER_PAGE(self) ((LadderPage*)(self)) -#define LADDER_PAGE_DESCRIPTOR(self) ((LadderPageDescriptor*)(self)) - -LadderPageDescriptor *ladder_page_descriptor_init(LadderPageDescriptor *self, int width, int height, - ScrollType direction, float page_size, float vstep, - float vsubstep, LPInitFunc func); -void ladder_page_descriptor_compute_offset(LadderPageDescriptor *self, float ppv); -LadderPage *ladder_page_descriptor_create_page(LadderPageDescriptor *self, int index); - - -LadderPage *ladder_page_new(float start, LadderPageDescriptor *descriptor); -LadderPage *ladder_page_init(LadderPage *self); -void ladder_page_free(LadderPage *self); - -int ladder_page_get_index(LadderPage *self); -float ladder_page_resolve_value(LadderPage *self, float value); -void ladder_page_draw_ruler(LadderPage *self, uint8_t base_unit_px, - LadderPageRulerLocation location, uint8_t small_step_width, uint8_t big_step_width); -void ladder_page_etch_markings(LadderPage *self, PCF_Font *font, uint halign, int offset); -#endif /* LADDER_PAGE_H */ diff --git a/main.c b/main.c deleted file mode 100644 index 17edd72..0000000 --- a/main.c +++ /dev/null @@ -1,541 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include -#include - -#include - -#include "base-gauge.h" -#include "basic-hud.h" -#include "dialogs/direct-to-dialog.h" -#include "side-panel.h" -#include "map-gauge.h" -#include "resource-manager.h" -#include "sdl-colors.h" -#include "widgets/base-widget.h" - -#if ENABLE_3D -#include "terrain-viewer.h" -#endif - -#define ENABLE_FGCONN 1 -#define ENABLE_FGTAPE 1 -#define ENABLE_SENSORS 1 -#define ENABLE_STRATUX 1 -#define ENABLE_MOCK 1 - -#include "data-source.h" -#if ENABLE_FGCONN -#include "fg-data-source.h" -#endif -#if ENABLE_FGTAPE -#include "fg-tape-data-source.h" -#endif -#if ENABLE_SENSORS -#include "sensors-data-source.h" -#endif -#if ENABLE_STRATUX -#include "stratux-data-source.h" -#endif -#if ENABLE_MOCK -#include "mock-data-source.h" -#endif - -#define SCREEN_WIDTH 640 -#define SCREEN_HEIGHT 480 - -#define N_COLORS 4 - -typedef enum{ - MODE_FGREMOTE, - MODE_FGTAPE, - MODE_SENSORS, - MODE_STRATUX, - MODE_MOCK, - N_MODES -}RunningMode; - -BasicHud *hud = NULL; -SidePanel *panel = NULL; -MapGauge *map = NULL; -DirectToDialog *ddt = NULL; - -bool g_show3d = false; -DataSource *g_ds; -RunningMode g_mode; - -/*Return true to quit the app*/ -bool handle_keyboard(SDL_KeyboardEvent *event, Uint32 elapsed) -{ - AttitudeData new_attitude; - LocationData new_location; - bool attitude_dirty = false; - bool location_dirty = false; - - new_attitude = g_ds->attitude; - new_location = g_ds->location; - - if(ddt && ddt->visible) - base_widget_handle_event(BASE_WIDGET(ddt), event); - - switch(event->keysym.sym){ - /*App control*/ - case SDLK_ESCAPE: - if(event->state == SDL_PRESSED) - return true; - break; - case SDLK_SPACE: - if(event->state == SDL_PRESSED) - g_show3d = !g_show3d; - hud->attitude->mode = (g_show3d) ? AI_MODE_3D : AI_MODE_2D; - break; - case SDLK_RETURN: - if(event->state == SDL_PRESSED){ - if(g_mode == MODE_FGTAPE) - ((FGTapeDataSource*)(g_ds))->playing = !((FGTapeDataSource*)(g_ds))->playing; - } - break; - case SDLK_p: - if(event->state == SDL_PRESSED){ - printf("Pitch: %f\nHeading: %f\n", - g_ds->attitude.pitch, - g_ds->attitude.heading - ); - } - break; - - /*MapGauge controls*/ - case SDLK_KP_8: /*keypad up arrows*/ - if(event->state == SDL_PRESSED){ - map_gauge_manipulate_viewport(map, 0, -10, true); - } - break; - case SDLK_KP_2: /*keypad down arrows*/ - if(event->state == SDL_PRESSED){ - map_gauge_manipulate_viewport(map, 0, 10, true); - } - break; - case SDLK_KP_4: /*keypad left arrows*/ - if(event->state == SDL_PRESSED){ - map_gauge_manipulate_viewport(map, -10, 0, true); - } - break; - case SDLK_KP_6: /*keypad right arrows*/ - if(event->state == SDL_PRESSED){ - map_gauge_manipulate_viewport(map, 10, 0, true); - } - break; - case SDLK_KP_PLUS: - if(event->state == SDL_PRESSED){ - map_gauge_set_level(map, map->level+1); - } - break; - case SDLK_KP_MINUS: - if(event->state == SDL_PRESSED){ - map_gauge_set_level(map, map->level-1); - } - break; - case SDLK_KP_DIVIDE: - if(event->state == SDL_PRESSED){ - map_gauge_center_on_marker(map, true); - } - break; - - /*Go to dialog*/ - case SDLK_g: - if(event->state == SDL_PRESSED){ - if(!ddt) - ddt = direct_to_dialog_new(); - else - direct_to_dialog_reset(ddt); - ddt->visible = true; - } - break; - - /*Manual camera/position control*/ - case SDLK_z: - if(event->state == SDL_PRESSED){ - new_attitude.pitch += 1.0; - attitude_dirty = true; - } - break; - case SDLK_s: - if(event->state == SDL_PRESSED){ - new_attitude.pitch -= 1.0; - attitude_dirty = true; - } - break; - case SDLK_q: - if(event->state == SDL_PRESSED){ - new_attitude.roll -= 1.0; - attitude_dirty = true; - } - break; - case SDLK_d: - if(event->state == SDL_PRESSED){ - new_attitude.roll += 1.0; - attitude_dirty = true; - } - break; - case SDLK_a: - if(event->state == SDL_PRESSED){ - new_attitude.heading -= 1.0; - new_attitude.heading = fmodf(new_attitude.heading, 360.0); - attitude_dirty = true; - } - break; - case SDLK_e: - if(event->state == SDL_PRESSED){ - new_attitude.heading += 1.0; - new_attitude.heading = fmodf(new_attitude.heading, 360.0); - attitude_dirty = true; - } - break; - case SDLK_PAGEUP: - if(event->state == SDL_PRESSED){ - new_location.altitude += 10; - attitude_dirty = true; - } - break; - case SDLK_PAGEDOWN: - if(event->state == SDL_PRESSED){ - new_location.altitude -= 10; - attitude_dirty = true; - } - break; - } - if(attitude_dirty) - data_source_set_attitude(g_ds, &new_attitude); - if(location_dirty) - data_source_set_location(g_ds, &new_location); - return false; -} - -/*Return true to quit the app*/ -bool handle_events(Uint32 elapsed) -{ - SDL_Event event; - - while(SDL_PollEvent(&event) == 1){ - switch(event.type){ - case SDL_QUIT: - return true; - break; - case SDL_WINDOWEVENT: - if(event.window.event == SDL_WINDOWEVENT_CLOSE) - return true; - break; - case SDL_KEYUP: - case SDL_KEYDOWN: - return handle_keyboard(&(event.key), elapsed); - break; - } - } - return false; -} - -const char *pretty_mode(RunningMode mode) -{ - switch(mode){ - case MODE_FGREMOTE: - return "FGDataSource"; - case MODE_FGTAPE: - return "FGTapeDataSource"; - case MODE_SENSORS: - return "SensorsDataSource"; - case MODE_STRATUX: - return "StratuxDataSource"; - case MODE_MOCK: - return "MockDataSource"; - - default: - return "Unknown!"; - } - -} - -#if ENABLE_3D -void update_terrain_viewer_location(TerrainViewer *self, LocationData *newv) -{ - double lon = fmod(newv->super.longitude+180, 360.0) - 180; - plane_set_position(self->plane, newv->super.latitude, lon, newv->altitude/3.281 + 2); - self->dirty = true; - /*printf("Position set to: lat:%f lon:%f alt:%f\n", newv->super.latitude, lon, newv->altitude);*/ - /*exit(0);*/ -} - -void update_terrain_viewer_attitude(TerrainViewer *self, AttitudeData *newv) -{ - plane_set_attitude(self->plane, newv->roll, newv->pitch, newv->heading); - self->dirty = true; -} -#endif - -int main(int argc, char **argv) -{ - Uint32 colors[N_COLORS]; - bool done; - int i; - float oldv[5] = {0,0,0,0,0}; - RenderTarget rtarget; - - g_mode = MODE_FGTAPE; - if(argc > 1){ - if(!strcmp(argv[1], "--sensors")) - g_mode = MODE_SENSORS; - else if(!strcmp(argv[1], "--fgtape")) - g_mode = MODE_FGTAPE; - else if(!strcmp(argv[1], "--fgremote")) - g_mode = MODE_FGREMOTE; - else if(!strcmp(argv[1], "--stratux")) - g_mode = MODE_STRATUX; - else if(!strcmp(argv[1], "--mock")) - g_mode = MODE_MOCK; - } - - switch(g_mode){ - case MODE_SENSORS: - g_ds = (DataSource *)sensors_data_source_new(); - break; - case MODE_FGREMOTE: - g_ds = (DataSource *)fg_data_source_new(6789); - break; - case MODE_STRATUX: - g_ds = (DataSource *)stratux_data_source_new(); - break; - case MODE_MOCK: - g_ds = (DataSource*)mock_data_source_new(); - break; - case MODE_FGTAPE: //Fallthtough - default: - g_ds = (DataSource *)fg_tape_data_source_new("fg-io/fg-tape/dr400.fgtape", 120); - break; - } - - if(!g_ds){ - printf("Couldn't create DataSource (%s), bailing out\n", pretty_mode(g_mode)); - exit(EXIT_FAILURE); - } - data_source_set(g_ds); - -#if USE_SDL_GPU - GPU_Target* gpu_screen = NULL; - - GPU_SetRequiredFeatures(GPU_FEATURE_BASIC_SHADERS); -#if USE_GLES - gpu_screen = GPU_InitRenderer(GPU_RENDERER_GLES_2, SCREEN_WIDTH, SCREEN_HEIGHT, GPU_DEFAULT_INIT_FLAGS); -#else - gpu_screen = GPU_InitRenderer(GPU_RENDERER_OPENGL_2, SCREEN_WIDTH, SCREEN_HEIGHT, GPU_DEFAULT_INIT_FLAGS); -#endif - if(gpu_screen == NULL){ - GPU_LogError("Initialization Error: Could not create a renderer with proper feature support for this demo.\n"); - return 1; - } - rtarget.target = gpu_screen; -#else - SDL_Window* window = NULL; - SDL_Surface* screenSurface = NULL; - - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - return 1; - } - - window = SDL_CreateWindow( - "HUD testbench", - SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - SCREEN_WIDTH, SCREEN_HEIGHT, - SDL_WINDOW_SHOWN - ); - if (window == NULL) { - fprintf(stderr, "could not create window: %s\n", SDL_GetError()); - return 1; - } - - screenSurface = SDL_GetWindowSurface(window); - if(!screenSurface){ - printf("Error: %s\n",SDL_GetError()); - exit(-1); - } - rtarget.surface = screenSurface; - - colors[0] = SDL_MapRGB(screenSurface->format, 0xFF, 0xFF, 0xFF); - colors[1] = SDL_MapRGB(screenSurface->format, 0xFF, 0x00, 0x00); - colors[2] = SDL_MapRGB(screenSurface->format, 0x00, 0xFF, 0x00); - colors[3] = SDL_MapRGB(screenSurface->format, 0x11, 0x56, 0xFF); -#endif - SDL_ShowCursor(SDL_DISABLE); - - SDL_Rect whole = {0,0,640,480}; - hud = basic_hud_new(); - - panel = side_panel_new(-1, -1); - SDL_Rect sprect = {0,0, base_gauge_w(BASE_GAUGE(panel)),base_gauge_h(BASE_GAUGE(panel))}; - - map = map_gauge_new(190,150); - map->level = 7; - SDL_Rect maprect = {SCREEN_WIDTH-200,SCREEN_HEIGHT-160,base_gauge_w(BASE_GAUGE(map)),base_gauge_h(BASE_GAUGE(map))}; - - SDL_Rect ddtrect ={ - 640/2, - 480/2 - 100, - 12*20, - 304 - }; - -#if ENABLE_3D - TerrainViewer *viewer; - viewer = terrain_viewer_new(-0.2); -#endif - - done = false; - Uint32 ticks; - Uint32 last_ticks = 0; - Uint32 elapsed = 0; - Uint32 acc = 0; - i = 3; - - Uint32 startms, dtms, last_dtms; - Uint32 nframes = 0; - Uint32 render_start, render_end; - Uint32 total_render_time = 0; - Uint32 nrender_calls = 0; -#if ENABLE_3D - g_show3d = true; -#endif - hud->attitude->mode = (g_show3d) ? AI_MODE_3D : AI_MODE_2D; - - if(g_mode == MODE_FGREMOTE) - fg_data_source_banner((FGDataSource*)g_ds); - - data_source_add_events_listener(g_ds, hud, 3, - ATTITUDE_DATA, basic_hud_attitude_changed, - DYNAMICS_DATA, basic_hud_dynamics_changed, - LOCATION_DATA, basic_hud_location_changed - ); - - data_source_add_listener(g_ds, ENGINE_DATA, &(ValueListener){ - .callback = (ValueListenerFunc)side_panel_engine_data_changed, - .target = panel - }); - - data_source_add_events_listener(g_ds, map, 3, - LOCATION_DATA, map_gauge_location_changed, - ATTITUDE_DATA, map_gauge_attitude_changed, - ROUTE_DATA, map_gauge_route_changed - ); - -#if ENABLE_3D - data_source_add_events_listener(g_ds, viewer, 2, - LOCATION_DATA, update_terrain_viewer_location, - ATTITUDE_DATA, update_terrain_viewer_attitude - ); -#endif - data_source_print_listener_stats(g_ds); - - printf("Waiting for fix."); - do{ - data_source_frame(DATA_SOURCE(g_ds), 0); - printf("."); - fflush(stdout); - sleep(1); /*sleep for 1 sec*/ - }while(!DATA_SOURCE(g_ds)->has_fix); - printf("\n"); - - - last_dtms = 0; - startms = SDL_GetTicks(); - do{ - ticks = SDL_GetTicks(); - elapsed = ticks - last_ticks; - dtms = ticks - startms; - - done = handle_events(elapsed); - - if(data_source_frame(DATA_SOURCE(g_ds), dtms - last_dtms)){ - last_dtms = dtms; - -#if ENABLE_3D - if(last_ticks == 0){ //Do an invisible frame to trigger preload - GPU_FlushBlitBuffer(); /*begin 3*/ - terrain_viewer_frame(viewer); - GPU_ResetRendererState(); /*end 3d*/ - /*Reset startms as initial loading can take up a while*/ - startms = SDL_GetTicks(); - } -#endif - } -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif -#if ENABLE_3D - if(g_show3d){ - GPU_FlushBlitBuffer(); /*begin 3*/ - glDisable(GL_BLEND); - terrain_viewer_frame(viewer); - GPU_ResetRendererState(); /*end 3d*/ - } -#endif - render_start = SDL_GetTicks(); - base_gauge_render(BASE_GAUGE(hud), elapsed, &(RenderContext){rtarget, &whole, NULL}); - base_gauge_render(BASE_GAUGE(panel), elapsed, &(RenderContext){rtarget, &sprect, NULL}); - base_gauge_render(BASE_GAUGE(map), elapsed, &(RenderContext){rtarget, &maprect, NULL}); - if(ddt && ddt->visible) - base_gauge_render(BASE_GAUGE(ddt), elapsed, &(RenderContext){rtarget, &ddtrect, NULL}); - render_end = SDL_GetTicks(); - total_render_time += render_end - render_start; - nrender_calls++; - -#if USE_SDL_GPU - GPU_Flip(gpu_screen); -#else - SDL_UpdateWindowSurface(window); -#endif - nframes++; - acc += elapsed; - if(elapsed < 20){ - SDL_Delay(20 - elapsed); - } - if(acc >= 1000){ /*1sec*/ - int h,m,s; - - h = dtms/3600000; - dtms -= dtms/3600000 * h; - m = dtms / 60000; - dtms -= 60000 * m; - s = dtms / 1000; - - printf("%02d:%02d:%02d Current FPS: %03d\r",h,m,s, (1000*nframes)/elapsed); - fflush(stdout); - nframes = 0; - acc = 0; - } - i %= N_COLORS; - last_ticks = ticks; - }while(!done); - - printf("Average rendering time (%d samples): %f ticks\n", nrender_calls, total_render_time*1.0/nrender_calls); - base_gauge_free(BASE_GAUGE(hud)); - base_gauge_free(BASE_GAUGE(panel)); - base_gauge_free(BASE_GAUGE(map)); - data_source_free(DATA_SOURCE(g_ds)); - resource_manager_shutdown(); -#if ENABLE_3D - terrain_viewer_free(viewer); - texture_store_shutdown(); -#endif -#if USE_SDL_GPU - GPU_Quit(); -#else - SDL_DestroyWindow(window); - SDL_Quit(); -#endif - return 0; -} diff --git a/map-gauge.c b/map-gauge.c deleted file mode 100644 index 8120193..0000000 --- a/map-gauge.c +++ /dev/null @@ -1,617 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include - -#include "base-gauge.h" -#include "data-source.h" -#include "generic-layer.h" -#include "map-gauge.h" -#include "map-math.h" -#include "map-tile-cache.h" -#include "map-provider.h" -#include "static-map-provider.h" -#include "route-map-provider.h" -#include "misc.h" -#include "sdl-colors.h" -#include "res-dirs.h" - -#include "SDL_surface.h" -#include "SDL_timer.h" - -/*Each tile is 256x256 px*/ -#define TILE_SIZE 256 -/*Time after which the viewport re-ties to the marker*/ -#define MANIPULATE_TIMEOUT 2000 -/* Scroll when the marker bouding box reaches this limit around the viewport*/ -#define PIX_LIMIT 10 - -#define map_gauge_marker_left(self) ((self)->marker.x - generic_layer_w(&(self)->marker.layer)/2) -#define map_gauge_marker_top(self) ((self)->marker.y - generic_layer_h(&(self)->marker.layer)/2) - -#define map_gauge_marker_worldbox(self) (SDL_Rect){ \ - .x = map_gauge_marker_left(self), \ - .y = map_gauge_marker_top(self), \ - .w = generic_layer_w(&(self)->marker.layer), \ - .h = generic_layer_h(&(self)->marker.layer) \ -} - - -#define map_gauge_viewport(self) (SDL_Rect){ \ - .x = (self)->world_x, \ - .y = (self)->world_y, \ - .w = base_gauge_w(BASE_GAUGE((self))), \ - .h = base_gauge_h(BASE_GAUGE((self))) \ -} - - -static void map_gauge_render(MapGauge *self, Uint32 dt, RenderContext *ctx); -static void map_gauge_update_state(MapGauge *self, Uint32 dt); -static MapGauge *map_gauge_dispose(MapGauge *self); -static BaseGaugeOps map_gauge_ops = { - .render = (RenderFunc)map_gauge_render, - .update_state = (StateUpdateFunc)map_gauge_update_state, - .dispose = (DisposeFunc)map_gauge_dispose -}; - -/** - * @brief Creates a new MapGauge of given dimensions. - * - * Caller is responsible for freeing the gauge by calling - * base_gauge_free. - * - * @param w Width (in pixels) of the gauge - * @param h Height (in pixels) of the gauge - * @return a newly-allocated MapGauge on success, NULL on failure. - * - * @see base_gauge_free - */ -MapGauge *map_gauge_new(int w, int h) -{ - MapGauge *rv; - - rv = calloc(1, sizeof(MapGauge)); - if(rv){ - if(!map_gauge_init(rv,w,h)) - return base_gauge_free(BASE_GAUGE(rv)); - } - return rv; -} - -/** - * @brief Inits an already allocated MapGauge with given dimensions. - * - * This function must not be called twice on the same object - * without calling map_gauge_dispose inbetween. - * - * @param self a MapGauge - * @param w Width (in pixels) of the gauge - * @param h Height (in pixels) of the gauge - * @return @p self on success, NULL on failure. - * - * @see map_gauge_dispose - * @see map_gauge_new - */ -MapGauge *map_gauge_init(MapGauge *self, int w, int h) -{ - int twidth, theight; - size_t cache_tiles; - - base_gauge_init(BASE_GAUGE(self), - &map_gauge_ops, - w, h - ); - - twidth = w / TILE_SIZE; - theight = h /TILE_SIZE; - /* Worst case is the view centered on the junction of 4 tiles - * multiplied by the number of tiles the view can see at once. - * with a minimum of 1 if the view is smaller than a tile - */ - /*Keep in the tile stack 2 viewports worth of tiles*/ - cache_tiles = (MAX(twidth, 1) * MAX(twidth, 1)) * 4; - map_tile_cache_init(&self->tile_cache, cache_tiles); - - /*TODO: Runtime / GUI selection of maps*/ -#if HAVE_IGN_OACI_MAP - self->tile_providers[self->ntile_providers++] = (MapProvider*)static_map_provider_new( - MAPS_HOME"/ign-oaci", "jpg",0 - ); -#else - self->tile_providers[self->ntile_providers++] = (MapProvider*)static_map_provider_new( - MAPS_HOME"/osm", "png", 0 - ); -#endif - -#if !HAVE_IGN_OACI_MAP - self->overlays[self->noverlays++] = (MapProvider*)static_map_provider_new( - MAPS_HOME"/openaip", "png", 0 - ); -#endif - - self->route_overlay = route_map_provider_new(); - if(!self->route_overlay) - return NULL; - - qsort(self->tile_providers, - self->ntile_providers, - sizeof(MapProvider*), (__compar_fn_t)map_provider_compare_ptr - ); - qsort(self->overlays, - self->noverlays, - sizeof(MapProvider*), (__compar_fn_t)map_provider_compare_ptr - ); - - - /*TODO: Scale the plane relative to the gauge's size*/ - generic_layer_init_from_file(&self->marker.layer, IMG_DIR"/plane32.png"); - generic_layer_build_texture(&self->marker.layer); - - return self; -} - -/** - * @brief Release any resources internally held by the MapGauge - * - * This function always returns NULL (convenience behavior). - * - * @param self a MapGauge - * @return NULL - */ -static MapGauge *map_gauge_dispose(MapGauge *self) -{ - for(int i = 0; i < self->state.npatches; i++) - generic_layer_unref(self->state.patches[i].layer); - if(self->state.patches) - free(self->state.patches); - - generic_layer_dispose(&self->marker.layer); - for(int i = 0; i < self->ntile_providers; i++) - map_provider_free(self->tile_providers[i]); - - for(int i = 0; i < self->noverlays; i++) - map_provider_free(self->overlays[i]); - - map_provider_free(MAP_PROVIDER(self->route_overlay)); - map_tile_cache_dispose(&self->tile_cache); - return self; -} - -/** - * @brief Sets the current zoom level show by the gauge. Valid levels are - * 0 to MAP_GAUGE_MAX_LEVEL, owing to types internally used to store positions. - - * The current maximum level is 23 with ints (32 bits) which is more than - * sufficient for aviation purposes - * - * This function will try its best to keep the current area and zoom on it. - * - * @param self a MapGauge - * @param level the level to show - * @return true on success, false on failure (level unsupported, ...) - */ -bool map_gauge_set_level(MapGauge *self, uintf8_t level) -{ - double lat, lon; - int32_t new_x, new_y; - - if(level > 15) - return false; - if(level != self->level){ - /* Keep the view at the same place. TODO: There should be a way to do the - * same without having to go through geo coords transforms*/ - map_math_pixel_to_geo(self->world_x, self->world_y, self->level, &lat, &lon); - map_math_geo_to_pixel(lat, lon, level, &new_x, &new_y); - /*Same for the marker*/ - map_math_pixel_to_geo(self->marker.x, self->marker.y, self->level, &lat, &lon); - self->level = level; - map_gauge_set_viewport(self, new_x, new_y, false); - map_gauge_set_marker_position(self, lat, lon); - } - return true; -} - -/** - * @brief Updates the marker position - * - * Client code should use this function to make the marker move. - * - * @param self a MapGauge - * @param latitude The new latitude of the marker - * @param longitude The new longitude of the marker - * @return true on success, false on failure. - */ -bool map_gauge_set_marker_position(MapGauge *self, double latitude, double longitude) -{ - bool rv; - int32_t new_x,new_y; - - /* TODO: This is purely based on time and should not be in this function - * it should be some kind of animation or use another system to have - * time-based events - * */ - if(self->roaming && SDL_GetTicks() - self->last_manipulation > MANIPULATE_TIMEOUT){ - self->roaming = false; - map_gauge_center_on_marker(self, true); - } - - rv = map_math_geo_to_pixel(latitude, longitude, self->level, &new_x, &new_y); - if(new_x != self->marker.x || new_y != self->marker.y){ - self->marker.x = new_x; - self->marker.y = new_y; - if(!self->roaming){ - map_gauge_follow_marker(self); - } - BASE_GAUGE(self)->dirty = true; - return true; - } - return false; -} - -/** - * @brief Updates the marker heading (dregrees, 0-360). If the value - * is outside the valid range, it will be clamped to it. - * - * Client code should use this function to make the marker face - * the direction it's heading towards. - * - * @param self a MapGauge - * @param heading The new heading of the marker, in degrees - * @return true on success, false on failure. - */ -bool map_gauge_set_marker_heading(MapGauge *self, float heading) -{ - heading = clampf(heading, 0, 360); - if(heading != self->marker.heading){ - self->marker.heading = heading; - BASE_GAUGE(self)->dirty = true; - return true; - } - return false; -} - -/** - * @brief Moves the viewport by the given increment while putting it in a - * temporary 'roaming' mode. Roaming mode will last MANIPULATE_TIMEOUT ms - * after the last call to map_gauge_manipulate_viewport. - * - * While in roaming mode, the viewport is free to roam the entire map without - * being dragged back when the marker moves. Once the roaming mode expires, the - * viewport automatically goes back centered on the marker position. - * - * This function is intended to be called by 'client' code. - * - * @param self a MapGauge - * @param dx increment for the x position, positive or negative - * @param dy increment for the y position, positive or negative - * @param animated When true, will show a nice transition from the current - * viewport position to the aforementioned area. - * @return true on success, false on failure. - */ -bool map_gauge_manipulate_viewport(MapGauge *self, int32_t dx, int32_t dy, bool animated) -{ - self->last_manipulation = SDL_GetTicks(); - self->roaming = true; - return map_gauge_set_viewport(self, - self->world_x + dx, - self->world_y + dy, - animated - ); -} - -/** - * @brief Resets the viewport to show the area surrounding the marker - * with the marker in the center. - * - * Client code can use this function to reset the view on command. Doing - * so is not mandatory as the default behavior of the gauge is to go back - * to a marker-on-center position when: - * -Roaming mode expores, @see map_gauge_manipulate_viewport - * -The marker reaches the edges of the current viewport - * - * @param self a MapGauge - * @param animated When true, will show a nice transition from the current - * viewport position to the aforementioned area. - * @return true on success, false on failure. - */ -bool map_gauge_center_on_marker(MapGauge *self, bool animated) -{ - return map_gauge_set_viewport(self, - map_gauge_marker_left(self) - base_gauge_center_x(BASE_GAUGE(self)), - map_gauge_marker_top(self) - base_gauge_center_y(BASE_GAUGE(self)), - animated - ); -} - -/** - * @brief Move the viewport according to the current marker position - * - * Mainly internal function - * - * @param self a MapGauge - * @return true on success, false on failure - */ -bool map_gauge_follow_marker(MapGauge *self) -{ - bool visible; - - visible = SDL_IntersectRect(&map_gauge_viewport(self), - &map_gauge_marker_worldbox(self), - &self->state.marker_src - ); - if(!visible){ - return map_gauge_center_on_marker(self, true); - } - - /*marker_x and marker_y are top left coordinates (world)*/ - if( map_gauge_marker_left(self) <= self->world_x + PIX_LIMIT - || map_gauge_marker_left(self) + generic_layer_w(&self->marker.layer) >= self->world_x + base_gauge_w(BASE_GAUGE(self)) - PIX_LIMIT - || map_gauge_marker_top(self) <= self->world_y + PIX_LIMIT - || map_gauge_marker_top(self) + generic_layer_h(&self->marker.layer) >= self->world_x + base_gauge_h(BASE_GAUGE(self)) - PIX_LIMIT - ) - return map_gauge_center_on_marker(self, true); - return true; -} - -/** - * @brief Moves the viewport by the given increment (in pixels). - * - * Mainly for interal use, might not be the function you are looking for. - * @see map_gauge_manipulate_viewport - * - * @param self a MapGauge - * @param dx increment for the x position, positive or negative - * @param dy increment for the y position, positive or negative - * @param animated When true, will show a nice transition from the current - * viewport position to the aforementioned area. - * @return true on success, false on failure. - */ -bool map_gauge_move_viewport(MapGauge *self, int32_t dx, int32_t dy, bool animated) -{ - return map_gauge_set_viewport(self, - self->world_x + dx, - self->world_y + dy, - animated - ); -} - -/** - * @brief Sets the viewport to the given position (in pixels). The position - * is a "world" position in the virtual current map level that goes from - * 0,0 to (256*2^level)-1,(256*2^level)-1. - * - * This function takes an absolute position to go to. For a movement relative - * to the current position, @see map_gauge_move_viewport. - * - * Mainly for interal use, might not be the function you are looking for. - * @see map_gauge_manipulate_viewport - * - * @param self a MapGauge - * @param x The new absolute x position - * @param y The new absolute y position - * @param animated When true, will show a nice transition from the current - * viewport position to the aforementioned area. - * @return true on success, false on failure. - */ -bool map_gauge_set_viewport(MapGauge *self, int32_t x, int32_t y, bool animated) -{ - uint32_t map_lastcoord = map_math_size(self->level) - 1; - x = clamp(x, 0, map_lastcoord - base_gauge_w(BASE_GAUGE(self))); - y = clamp(y, 0, map_lastcoord - base_gauge_h(BASE_GAUGE(self))); - - if(x == self->world_x && y == self->world_y) - return false; - - animated = false; - if(animated){ - /*start an animation that moves current coords to their - * destination values*/ - }else{ - self->world_x = x; - self->world_y = y; - BASE_GAUGE(self)->dirty = true; - } - return true; -} - -static GenericLayer *map_gauge_get_tile(MapGauge *self, uintf8_t level, int32_t x, int32_t y) -{ - GenericLayer *rv; - - rv = map_tile_cache_get(&self->tile_cache, level, x, y); - if(rv) - return rv; - - /* Cache miss, get tile from providers and cache it - * - * Providers are sorted by priority. The first provider - * to respond will have its tile used. If the a provider - * priority is negative, no overlay will be applied - * */ - for(int i = 0; i < self->ntile_providers; i++){ - rv = map_provider_get_tile(self->tile_providers[i], - level, x, y - ); - if(rv){ - if(self->tile_providers[i]->priority < 0 ) - goto end; - break; - } - } - if(!rv) return NULL;//No-one has the tile, bail out - /* If the selected provider wasn't a negative priority - * provider, apply all overlays on the tile - * */ - GenericLayer *tmp; - for(int i = 0; i < self->noverlays; i++){ - tmp = map_provider_get_tile(self->overlays[i], level, x, y); - if(!tmp) continue; - SDL_BlitSurface( - tmp->canvas, NULL, - rv->canvas,NULL - ); - generic_layer_free(tmp); - } - - /*Apply the route drawing, if any*/ - tmp = map_provider_get_tile(MAP_PROVIDER(self->route_overlay), level, x, y); - if(tmp){ - SDL_BlitSurface( - tmp->canvas, NULL, - rv->canvas,NULL - ); - generic_layer_free(tmp); - } -end: - generic_layer_build_texture(rv); - map_tile_cache_add(&self->tile_cache, rv, level, x, y); - return rv; -} - -void map_gauge_location_changed(MapGauge *self, LocationData *newv) -{ - map_gauge_set_marker_position(self, newv->super.latitude, newv->super.longitude); -} - -void map_gauge_attitude_changed(MapGauge *self, AttitudeData *newv) -{ - map_gauge_set_marker_heading(self, newv->heading); -} - -void map_gauge_route_changed(MapGauge *self, RouteData *newv) -{ - route_map_provider_set_route(self->route_overlay, - &newv->from, &newv->to - ); - map_tile_cache_clear(&self->tile_cache); - BASE_GAUGE(self)->dirty = true; -} - -/*TODO: split up*/ -static void map_gauge_update_state(MapGauge *self, Uint32 dt) -{ - /* We go up to level 23, which is 8388608 tiles - * (from 0 to 8388607) in both directions*/ - int32_t tl_tile_x, tl_tile_y; /*top left*/ - int32_t br_tile_x, br_tile_y; /*bottom right*/ - - tl_tile_x = self->world_x / TILE_SIZE; - tl_tile_y = self->world_y / TILE_SIZE; - - int32_t lastx = self->world_x + base_gauge_w(BASE_GAUGE(self)) - 1; - int32_t lasty = self->world_y + base_gauge_h(BASE_GAUGE(self)) - 1; - br_tile_x = lastx / TILE_SIZE; - br_tile_y = lasty / TILE_SIZE; - - int32_t x_tile_span = (br_tile_x - tl_tile_x) + 1; - int32_t y_tile_span = (br_tile_y - tl_tile_y) + 1; - int32_t tile_span = x_tile_span * y_tile_span; - - /*There will be as many patches as tiles over which we are located*/ - /* Currently an X,Y tile is the fusion of all X,Y tiles - * given by providers that can provide that tile. - */ - if(tile_span > self->state.apatches){ - void *tmp; - size_t stmp; - stmp = self->state.apatches; - self->state.apatches = tile_span; - tmp = realloc(self->state.patches, self->state.apatches*sizeof(MapPatch)); - if(!tmp){ - self->state.apatches = stmp; - return; - } - self->state.patches = tmp; - } - - for(int i = 0; i < self->state.npatches; i++) - generic_layer_unref(self->state.patches[i].layer); - self->state.npatches = 0; - - GenericLayer *layer; - SDL_Rect viewport = map_gauge_viewport(self); - for(int tiley = tl_tile_y; tiley <= br_tile_y; tiley++){ - for(int tilex = tl_tile_x; tilex <= br_tile_x; tilex++){ - layer = map_gauge_get_tile(self, self->level, tilex, tiley); - if(!layer) - printf("Couldn't get tile layer for tile x:%d y:%d zoom:%d\n",tilex,tiley, self->level); - if(!layer) continue; - /*TODO: Use rects with uint32_t, - * SDL uses ints and will only go up to level 15*/ - SDL_Rect tile = { - .x = TILE_SIZE * tilex, - .y = TILE_SIZE * tiley, - .w = TILE_SIZE, - .h = TILE_SIZE - }; - /*Get intersection of the tile with the viewport, in world coordinates*/ - SDL_IntersectRect(&viewport, - &tile, - &self->state.patches[self->state.npatches].src - ); - self->state.patches[self->state.npatches].dst = self->state.patches[self->state.npatches].src; - /*Change src to be in the tile's local coordinates (0-255)*/ - self->state.patches[self->state.npatches].src.x -= tile.x; - self->state.patches[self->state.npatches].src.y -= tile.y; - /*Change dst to be in the viewport's local coordinates (0-(w-1),0-(h-1)*/ - self->state.patches[self->state.npatches].dst.x -= self->world_x; - self->state.patches[self->state.npatches].dst.y -= self->world_y; - - self->state.patches[self->state.npatches].layer = layer; - generic_layer_ref(layer); - self->state.npatches++; - } - } - - /*Get intersection of the marker with the viewport, in world coordinates*/ - bool marker_visible = SDL_IntersectRect(&viewport, - &map_gauge_marker_worldbox(self), - &self->state.marker_src - ); - if(marker_visible){ - self->state.marker_dst = self->state.marker_src; - /*Change src to be in the marker's local coordinates (0-(w-1),0-(h-1)*/ - self->state.marker_src.x -= map_gauge_marker_left(self); - self->state.marker_src.y -= map_gauge_marker_top(self); - /*Change dst to be in the viewport's local coordinates (0-(w-1),0-(h-1)*/ - self->state.marker_dst.x -= self->world_x; - self->state.marker_dst.y -= self->world_y; - }else{ - self->state.marker_dst = (SDL_Rect){-1,-1,-1,-1}; - self->state.marker_src = self->state.marker_dst; - } -} - -static void map_gauge_render(MapGauge *self, Uint32 dt, RenderContext *ctx) -{ - MapPatch *patch; - - - for(int i = 0; i < self->state.npatches; i++){ - patch = &self->state.patches[i]; - base_gauge_blit_layer(BASE_GAUGE(self), ctx, - patch->layer, &patch->src, - &patch->dst - ); - } - if(self->state.marker_src.x >= 0){ -#if 0 - base_gauge_blit_layer(BASE_GAUGE(self), ctx, - &self->marker, - &self->state.marker_src, - &self->state.marker_dst - ); -#endif - base_gauge_blit_rotated_texture(BASE_GAUGE(self), ctx, - self->marker.layer.texture, &self->state.marker_src, - self->marker.heading, - NULL, - &self->state.marker_dst, - NULL); - } - base_gauge_draw_outline(BASE_GAUGE(self), ctx, &SDL_WHITE, NULL); -} diff --git a/map-gauge.h b/map-gauge.h deleted file mode 100644 index af16af5..0000000 --- a/map-gauge.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef MAP_GAUGE_H -#define MAP_GAUGE_H - -#include "base-gauge.h" -#include "generic-layer.h" -#include "map-tile-cache.h" -#include "map-provider.h" -#include "route-map-provider.h" -#include "data-source.h" -#include "misc.h" - -/* int(32) pixel coordinates go up to - * 2,147,483,647 which is the maximum coordinate - * of level 23 - */ -#define MAP_GAUGE_MAX_LEVEL 23 - -typedef struct{ - /*TODO: Array of pointers to layers, as much as providers/overlays*/ - GenericLayer *layer; - SDL_Rect src; - SDL_Rect dst; -}MapPatch; - -typedef struct{ - MapPatch *patches; - size_t apatches; - size_t npatches; - - SDL_Rect marker_src; - SDL_Rect marker_dst; -}MapGaugeState; - -typedef struct{ - GenericLayer layer; - /* Marker position in "world" coordinates - * world coordinates are respective to the - * current level. - * - * Note: this is the point marked, the icon - * itself is centered on these coordinates - */ - int32_t x; - int32_t y; - float heading; -}MapGaugeMarker; - -typedef struct{ - BaseGauge super; - - MapTileCache tile_cache; - /*current zoom level*/ - uintf8_t level; - /*Top-left coordinates of the viewport*/ - int32_t world_x; - int32_t world_y; - - /*The little plane on the map*/ - MapGaugeMarker marker; - - bool roaming; /*The view is roaming around and not tied to the marker*/ - Uint32 last_manipulation; - - MapProvider *tile_providers[2]; /*static for now*/ - size_t ntile_providers; - - MapProvider *overlays[1]; /*static for now*/ - size_t noverlays; - - RouteMapProvider *route_overlay; - - MapGaugeState state; -}MapGauge; - -MapGauge *map_gauge_new(int w, int h); -MapGauge *map_gauge_init(MapGauge *self, int w, int h); - -bool map_gauge_set_level(MapGauge *self, uintf8_t level); -bool map_gauge_set_marker_position(MapGauge *self, double latitude, double longitude); -bool map_gauge_set_marker_heading(MapGauge *self, float heading); -bool map_gauge_manipulate_viewport(MapGauge *self, int32_t dx, int32_t dy, bool animated); -bool map_gauge_center_on_marker(MapGauge *self, bool animated); - -bool map_gauge_follow_marker(MapGauge *self); -bool map_gauge_move_viewport(MapGauge *self, int32_t dx, int32_t dy, bool animated); -bool map_gauge_set_viewport(MapGauge *self, int32_t x, int32_t y, bool animated); - - -void map_gauge_location_changed(MapGauge *self, LocationData *newv); -void map_gauge_attitude_changed(MapGauge *self, AttitudeData *newv); -void map_gauge_route_changed(MapGauge *self, RouteData *newv); -#endif /* MAP_GAUGE_H */ diff --git a/map-math.c b/map-math.c deleted file mode 100644 index 71ece8f..0000000 --- a/map-math.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include -#include - -#include "map-math.h" -#include "misc.h" - -#define MIN_LATITUDE -85.05112878 -#define MAX_LATITUDE 85.05112878 -#define MIN_LONGITUDE -180 -#define MAX_LONGITUDE 180 - - -bool map_math_geo_to_pixel(double latitude, double longitude, uintf8_t level, int32_t *px, int32_t *py) -{ - latitude = map_math_clip(latitude, MIN_LATITUDE, MAX_LATITUDE); - longitude = map_math_clip(longitude, MIN_LONGITUDE, MAX_LONGITUDE); - - double x = (longitude + 180) / 360; - double sinLatitude = sin(latitude * M_PI / 180); - double y = 0.5 - log((1 + sinLatitude) / (1 - sinLatitude)) / (4 * M_PI); - - uint mapSize = map_math_size(level); - *px = (uint32_t) map_math_clip(x * mapSize + 0.5, 0, mapSize - 1); - *py = (uint32_t) map_math_clip(y * mapSize + 0.5, 0, mapSize - 1); - return true; -} - -void map_math_pixel_to_geo(int32_t px, int32_t py, uintf8_t level, double *latitude, double *longitude) -{ - double mapSize = map_math_size(level); - double x = (map_math_clip(px, 0, mapSize - 1) / mapSize) - 0.5; - double y = 0.5 - (map_math_clip(py, 0, mapSize - 1) / mapSize); - - *latitude = 90 - 360 * atan(exp(-y * 2 * M_PI)) / M_PI; - *longitude = 360 * x; -} diff --git a/map-math.h b/map-math.h deleted file mode 100644 index ff1d54e..0000000 --- a/map-math.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef MAP_MATH_H -#define MAP_MATH_H -#include -#include "misc.h" - -/*TODO: merge with clamp/clampd*/ -static inline double map_math_clip(double n, double minValue, double maxValue) -{ - return MIN(MAX(n, minValue), maxValue); -} - -static inline uint32_t map_math_size(uintf8_t level) -{ - return ((uint32_t)256) << level; -} - -bool map_math_geo_to_pixel(double latitude, double longitude, uintf8_t level, int32_t *px, int32_t *py); -void map_math_pixel_to_geo(int32_t px, int32_t py, uintf8_t level, double *latitude, double *longitude); -#endif /* MAP_MATH_H */ diff --git a/map-provider.c b/map-provider.c deleted file mode 100644 index a0d9071..0000000 --- a/map-provider.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif -#include -#include -#include -#include - -#include "map-provider.h" -#include "misc.h" - -MapProvider *map_provider_init(MapProvider *self, - MapProviderOps *ops, intf8_t priority) -{ - self->ops = ops; - self->priority = priority; - return self; -} - -MapProvider *map_provider_dispose(MapProvider *self) -{ - if(self->areas) - free(self->areas); - - if(self->ops->dispose) - self->ops->dispose(MAP_PROVIDER(self)); - return self; -} - -MapProvider *map_provider_free(MapProvider *self) -{ - free(map_provider_dispose(self)); - return NULL; -} - -bool map_provider_set_nareas(MapProvider *self, size_t nareas) -{ - if(nareas > self->nareas){ - void *tmp = realloc(self->areas, sizeof(MapProviderArea)*nareas); - if(!tmp) - return false; - memset( - (MapProviderArea*)tmp + self->nareas, - 0, - (nareas - self->nareas) * sizeof(MapProviderArea) - ); - self->areas = tmp; - self->nareas = nareas; - } - return true; -} - -bool map_provider_has_tile(MapProvider *self, uintf8_t level, int32_t x, int32_t y) -{ - int i; - - for(i = 0; i < self->nareas; i++){ - if(self->areas[i].level == level){ - return( (x >= self->areas[i].left) && (x <= self->areas[i].right) - && (y >= self->areas[i].top) && (y <= self->areas[i].bottom) - ); - } - } - - /*true if no area is registered, false if there is any and we got here*/ - return (i == 0); -} - -int map_provider_compare(MapProvider *self, MapProvider *other) -{ - if(self->priority < other->priority) - return -1; - if(self->priority > other->priority) - return 1; - return 0; -} - -int map_provider_compare_ptr(MapProvider **self, MapProvider **other) -{ - return map_provider_compare(*self, *other); -} - diff --git a/map-provider.h b/map-provider.h deleted file mode 100644 index 8f12219..0000000 --- a/map-provider.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef MAP_PROVIDER_H -#define MAP_PROVIDER_H -#include - -#include "generic-layer.h" -#include "misc.h" - -/* MAP_GAUGE_MAX_LEVEL 23 - * has 8388608 tiles from 0 to 8388607 - * which needs 24 bits. Nearest type is int32 - */ -typedef struct{ - uint8_t level; - - int32_t left; - int32_t right; - int32_t top; - int32_t bottom; -}MapProviderArea; - -typedef struct _MapProvider MapProvider; -typedef GenericLayer *(*MapProviderGetTileFunc)(MapProvider *self, - uintf8_t level, - int32_t x, int32_t y); -typedef MapProvider *(*MapProviderDisposeFunc)(MapProvider *self); -typedef struct{ - MapProviderGetTileFunc get_tile; - MapProviderDisposeFunc dispose; -}MapProviderOps; - -typedef struct _MapProvider{ - MapProviderOps *ops; - intf8_t priority; - - MapProviderArea *areas; - size_t nareas; -}MapProvider; - -#define MAP_PROVIDER(self) ((MapProvider*)(self)) - -MapProvider *map_provider_init(MapProvider *self, - MapProviderOps *ops, intf8_t priority); -MapProvider *map_provider_dispose(MapProvider *self); -MapProvider *map_provider_free(MapProvider *self); - -bool map_provider_set_nareas(MapProvider *self, size_t nareas); - -bool map_provider_has_tile(MapProvider *self, uintf8_t level, int32_t x, int32_t y); -static inline GenericLayer *map_provider_get_tile(MapProvider *self, uintf8_t level, int32_t x, int32_t y) -{ - return self->ops->get_tile(self, level, x, y); -} - - -int map_provider_compare(MapProvider *self, MapProvider *other); -int map_provider_compare_ptr(MapProvider **self, MapProvider **other); -#endif /* MAP_PROVIDER_H */ diff --git a/map-tile-cache.c b/map-tile-cache.c deleted file mode 100644 index 3e08914..0000000 --- a/map-tile-cache.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include - -#include "map-tile-cache.h" -#include "generic-layer.h" -#include "SDL_timer.h" - -static MapTileDescriptor *map_tile_cache_oldest(MapTileCache *self); - -MapTileCache *map_tile_cache_init(MapTileCache *self, size_t cache_size) -{ - self->acache = cache_size; - self->tile_cache = calloc(self->acache, sizeof(MapTileDescriptor)); - if(!self->tile_cache) - return NULL; - - return self; -} - - -MapTileCache *map_tile_cache_dispose(MapTileCache *self) -{ - - for(int i = 0; i < self->ncached; i++) - generic_layer_unref(self->tile_cache[i].layer); - - if(self->tile_cache) - free(self->tile_cache); - - return self; -} - -bool map_tile_cache_set_size(MapTileCache *self, uintf8_t cache_size) -{ - size_t old_size; - void *tmp; - - old_size = self->acache; - self->acache = cache_size; - tmp = realloc(self->tile_cache, self->acache * sizeof(MapTileDescriptor)); - if(!tmp){ - self->acache= old_size; - return false; - } - self->tile_cache = tmp; - /*clear cache ?*/ - return true; -} - -void map_tile_cache_clear(MapTileCache *self) -{ - for(int i = 0; i < self->ncached; i++) - generic_layer_unref(self->tile_cache[i].layer); - - self->ncached = 0; -} - -GenericLayer *map_tile_cache_get(MapTileCache *self, - uintf8_t level, int32_t x, int32_t y) -{ - for(int i = 0; i < self->ncached; i++){ - if(map_tile_descriptor_match(&self->tile_cache[i],level, x, y)){ - self->tile_cache[i].atime = SDL_GetTicks(); - return self->tile_cache[i].layer; - } - } - return NULL; -} - -bool map_tile_cache_add(MapTileCache *self, GenericLayer *tile, - uintf8_t level, int32_t x, int32_t y) -{ - generic_layer_ref(tile); - if(self->ncached == self->acache){ - MapTileDescriptor *slot; - - slot = map_tile_cache_oldest(self); - generic_layer_unref(slot->layer); - - *slot = (MapTileDescriptor){ - .layer = tile, - .level = level, - .x = x, - .y = y - }; - }else{ - self->tile_cache[self->ncached++] = (MapTileDescriptor){ - .layer = tile, - .level = level, - .x = x, - .y = y - }; - } - - return true; -} - -/** - * @brief Returns the cache location used by the least used descriptor - * (least recent last usage) - * - * MapTileDescriptor internal usage, not meant to be used by client code - * - * @param self a MapTileCache - * @return The slot location - */ -static MapTileDescriptor *map_tile_cache_oldest(MapTileCache *self) -{ - Uint32 now; - MapTileDescriptor *rv; - int rv_idx; - - now = SDL_GetTicks(); - rv_idx = 0; - for(int i = 0; i < self->ncached; i++){ - if(self->tile_cache[i].atime < now){ - rv_idx = i; - now = self->tile_cache[i].atime; - } - } - return &self->tile_cache[rv_idx]; -} - diff --git a/map-tile-cache.h b/map-tile-cache.h deleted file mode 100644 index f0a4219..0000000 --- a/map-tile-cache.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef MAP_TILE_CACHE_H -#define MAP_TILE_CACHE_H -#include -#include - -#include "generic-layer.h" -#include "misc.h" - -typedef struct{ - Uint32 atime; /*last access time in SDL_Ticks*/ - - /* MAP_GAUGE_MAX_LEVEL 23 - * has 8388608 tiles from 0 to 8388607 - * which needs 24 bits. Nearest type is int32 - */ - int32_t x; - int32_t y; - uintf8_t level; - GenericLayer *layer; -}MapTileDescriptor; - -typedef struct{ - MapTileDescriptor *tile_cache; - size_t acache; /*allocated size*/ - size_t ncached; /*currently holding*/ -}MapTileCache; - -MapTileCache *map_tile_cache_init(MapTileCache *self, size_t cache_size); -MapTileCache *map_tile_cache_dispose(MapTileCache *self); - -bool map_tile_cache_set_size(MapTileCache *self, uintf8_t cache_size); -GenericLayer *map_tile_cache_get(MapTileCache *self, - uintf8_t level, int32_t x, int32_t y); -bool map_tile_cache_add(MapTileCache *self, GenericLayer *tile, - uintf8_t level, int32_t x, int32_t y); - -void map_tile_cache_clear(MapTileCache *self); - -static inline bool map_tile_descriptor_match(MapTileDescriptor *self, - uintf8_t level, - int32_t x, int32_t y) -{ - return self->level == level - && self->x == x - && self->y == y; -} -#endif /* MAP_TILE_CACHE_H */ diff --git a/misc.c b/misc.c deleted file mode 100644 index 1b8aa4f..0000000 --- a/misc.c +++ /dev/null @@ -1,286 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "misc.h" - - - -/** - * Separate a base-10 number into its components: units, - * tens, hundreds, etc. The values will be laid out as - * n = parts[0] * 10^0 + parts[1]*10^2 ... + parts[x]*10^x - * (units) (tens) ... (rank x) - * i.e, the index in the array is the rank of the value - * stored at that index. - * - * @param n the value to split out - * @parts parts a pointer to a float array with enough - * space to hold all splitted out digits. - * @param p_size number of parts that @param parts can store - * @return the number of base-10 ranks that have been found - * - */ -int number_split(float n, float *parts, size_t p_size) -{ - int i = 1; - float val; - size_t rank = 0; - int divider; - - memset(parts, 0, sizeof(float)*p_size); - while(n > 0 && rank < p_size) { - val = fmod(n, 10) * i; - divider = pow(10, rank); - parts[rank] = val /= divider; -// printf("val: %f\n", val); - n = floor(n / 10); - i *= 10; - rank++; - } - return rank; -} - -/** - * Count the number of digits in n - * - */ -int number_digits(float n) -{ - int i = 1; - size_t rank = 0; - - while(n > 0 ) { - n = floor(n / 10); - i *= 10; - rank++; - } - return rank; -} - -bool interval_intersect(float as, float ae, float bs, float be, float *is, float *ie) -{ - if(bs > ae || as > be) - return false; - - *is = (as > bs) ? as : bs; - *ie = (ae < be) ? ae : be; - - return true; -} - -/** - * @brief Remove duplicates characters from base. base must be sorted - * so that duplicates follow each other (i.e. use qsort() beforehand). - * - * @param base The string to filter - * @param len The string len, -1 to have the function compute it. - */ -void filter_dedup(char *base, size_t len) -{ - len = len > -1 ? len : strlen(base); - - for(int i = 1; i < len; i++){ - if(base[i] == base[i-1]){ - int next; /*Next different char idx*/ - for(next = i; next < len && base[next] == base[i]; next++); - /* Index doesn't go OOB, last iteration will - * access (and move back) the final '\0' */ - for(int j = next; j < len+1; j++){ - base[i+(j-next)] = base[j]; - } - } - } -} - -/** - * @brief Returns the address of the first non-white space char in @parm str - * - * @param str The string to work on - * @param n go to at most n chars. 0 will be treated as strlen(str) - * @return Pointer to the first non-white space char (within str) or NULL if - * the whole string was whitespace - */ -char *nibble_spaces(const char *str, size_t n) -{ - char *iter; - const char *max; - - max = (n > 0) ? str+n : str+strlen(str); - for(iter = (char*)str; isspace(*iter) && iter < max; iter++); - - return (iter != max-1) ? iter : NULL; -} - -/** - * @brief Break a delimited (comma, space, etc.) string into a sequence of substrings. - * - * This function will fill @param parts with pointers to the begining of each of the - * detected parts. For example, a string like "one two three" will be splitted in 3 - * parts by a call to split_str using isspace(3) as splitter. The first pointer will - * point to the begining of the string, the second to the 't' of two and the third - * to the 't' of three. - * - * @param str The string to split - * @param splitter the function to use as the splitter. The libc provide many, refer - * to man isalpha(3) for a list. - * @param parts The array to be filled-in. If NULL, it won't be filled and the function - * will return the number of parts detected. - * @param nparts The number of pointers that @param parts can hold. Ignored if @param - * parts is NULL. - * @return The number of splitted/splittable elements. - */ -size_t split_str(const char *str, int (*splitter)(int c), char **parts, size_t nparts) -{ - char *iter; - const char *max; - size_t rv; - - rv = 0; - iter = (char*)str; - max = str+strlen(str); - do{ - while(splitter(*iter) && iter < max) iter++; - if(parts && rv < nparts) - parts[rv] = iter; - rv++; - while(!splitter(*iter) && iter < max) iter++; - }while(iter < max); - return rv-1; //Last increment is 'optimistic' -} - - -/** - * @brief Creates directory @param dir, creating parents as needed. - * - * Same behavior as the shell command mkdir -p - * - * - * @param dir The directory (path/hierarchy) to create - * @param mode The creation mode, bitfield of permissions. - * Refer to stat(2). - * - * credits: http://nion.modprobe.de/blog/archives/357-Recursive-directory-creation.html - */ -void mkdir_p(const char *dir, mode_t mode) -{ - char tmp[PATH_MAX]; - char *p = NULL; - size_t len; - - snprintf(tmp, sizeof(tmp),"%s",dir); - len = strlen(tmp); - if(tmp[len - 1] == '/') - tmp[len - 1] = 0; - for(p = tmp + 1; *p; p++){ - if(*p == '/') { - *p = 0; - mkdir(tmp, mode); - *p = '/'; - } - } - mkdir(tmp, mode); -} - -/** - * @brief Create all directories leading to @param filename - * - * @param filename Path to a file. - */ -bool create_path(const char *filename) -{ - char *tmp; - char *dname; - size_t len; - - /*dirname can modify its argument, so we need to make a copy*/ - len = strlen(filename); - if(len < 1024) - tmp = strdupa(filename); - else - tmp = strdup(filename); - dname = dirname(tmp); - - if(access(dname, F_OK) != 0) - mkdir_p(dname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); - if(len >= 1024) free(tmp); - - return access(dname, F_OK) == 0; -} - -/** - * Centers self on/in the reference rectangle. Self width - * and height *must* be set. - * - * @param self the SDL_Rect that is worked on. Must have w and h set. - * @param reference the rectangle that will have self in its center - */ -void SDLExt_RectCenter(SDL_Rect *self, SDL_Rect *reference) -{ - self->y = reference->y + round(reference->h/2.0 - self->h/2.0) -1; - self->x = reference->x + round(reference->w/2.0 - self->w/2.0) -1; -} - -/** - * Aligns self with/in the reference rectangle. Self width - * and height *must* be set. Alignemnt is controled by @param alignement - * - * @param self the SDL_Rect that is worked on. Must have w and h set. - * @param reference the rectangle that will have self in its center - * @param alignment bitwise combination of at most 2 VALIGN and HALIGN - * constants. Example: HALIGN_CENTER | VALIGN_MIDDLE. Passing 0 means TOP/LEFT - * alignment. - */ -void SDLExt_RectAlign(SDL_Rect *self, SDL_Rect *reference, uint8_t alignment) -{ - uint8_t valign, halign; - - halign = alignment & HALIGN_MASK; - valign = (alignment & VALIGN_MASK); - - /*Default alignment: left/bottom*/ - self->x = reference->x; - self->y = reference->y; - - if(halign == HALIGN_RIGHT){ - self->x += reference->w - self->w; - }else if(halign == HALIGN_CENTER){ - self->x += round(reference->w/2.0) - round(self->w/2.0); - } - - if(valign == VALIGN_BOTTOM){ - self->y += reference->h - self->h; - }else if(valign == VALIGN_MIDDLE){ - self->y += round(reference->h/2.0) - round(self->h/2.0); - } -} - - -void SDLExt_RectDump(SDL_Rect *self) -{ - printf("SDL_Rect(%p): x:%d, y:%d, w:%d, h:%d\n",self,self->x,self->y,self->w,self->h); -} - -/** - * @brief Comparison function for qsort() to sort chars in a string. - */ -int charcmp(const void *a, const void *b) -{ - return *(const char*)a - *(const char*)b; -} diff --git a/misc.h b/misc.h deleted file mode 100644 index e22f9a5..0000000 --- a/misc.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef MISC_H -#define MISC_H -#include -#include -#include -#include - -#include "SDL_rect.h" - -/* Note: Align NONE/LEFT and NONE/TOP are - * equivalent. - * */ -#define HALIGN_NONE 0x00 /*xxxxvv00*/ -#define HALIGN_LEFT 0x01 /*xxxxvv01*/ -#define HALIGN_RIGHT 0x02 /*xxxxvv10*/ -#define HALIGN_CENTER 0x03 /*xxxxvv11*/ -#define HALIGN_MASK 0x03 /*00000011*/ - -#define VALIGN_NONE 0x00 /*xxxx00hh*/ -#define VALIGN_TOP 0x04 /*xxxx01hh*/ -#define VALIGN_BOTTOM 0x08 /*xxxx10hh*/ -#define VALIGN_MIDDLE 0x0c /*xxxx11hh*/ -#define VALIGN_MASK 0x0c /*00001100*/ - -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) - - -typedef int_fast8_t intf8_t; -typedef uint_fast8_t uintf8_t; -typedef uint_fast16_t uintf16_t; - -int number_split(float n, float *parts, size_t p_size); -int number_digits(float n); - -bool interval_intersect(float as, float ae, float bs, float be, float *is, float *ie); - -void filter_dedup(char *base, size_t len); - -char *nibble_spaces(const char *str, size_t n); -size_t split_str(const char *str, int (*splitter)(int c), char **parts, size_t nparts); - -void mkdir_p(const char *dir, mode_t mode); -bool create_path(const char *filename); - -void SDLExt_RectCenter(SDL_Rect *self, SDL_Rect *reference); -void SDLExt_RectAlign(SDL_Rect *self, SDL_Rect *reference, uint8_t alignment); -void SDLExt_RectDump(SDL_Rect *self); - -int charcmp(const void *a, const void *b); - -#define SDLExt_RectLastX(rect) ((rect)->x + (rect)->w - 1) -#define SDLExt_RectLastY(rect) ((rect)->y + (rect)->h - 1) -#define SDLExt_RectMidY(rect) ((rect)->y + roundf(((rect)->h-1)/2.0f)) -#define SDLExt_RectMidX(rect) ((rect)->x + roundf(((rect)->w-1)/2.0f)) - -static inline int clamp(int x, int low, int high) -{ - return (x > high) ? high : ((x < low) ? low : x); -} - -static inline float clampf(float x, float low, float high) -{ - return (x > high) ? high : ((x < low) ? low : x); -} - -/* returns the next multiple of m that is at least x*/ -static inline int round_up(int x, int m) -{ - return x % m ? ((x / m) + 1) * m : x; -} - -#endif /* MISC_H */ diff --git a/mock-data-source.c b/mock-data-source.c deleted file mode 100644 index 061d7c1..0000000 --- a/mock-data-source.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include "mock-data-source.h" - -static bool mock_data_source_frame(MockDataSource *self, uint32_t dt); -static DataSourceOps mock_data_source_ops = { - .frame = (DataSourceFrameFunc)mock_data_source_frame, - .dispose = NULL -}; - - -MockDataSource *mock_data_source_new(void) -{ - MockDataSource *self; - - self = calloc(1, sizeof(MockDataSource)); - if(self){ - if(!mock_data_source_init(self)){ - data_source_free(DATA_SOURCE(self)); - return NULL; - } - } - return self; -} - -MockDataSource *mock_data_source_init(MockDataSource *self) -{ - if(!data_source_init(DATA_SOURCE(self), &mock_data_source_ops)) - return NULL; -#if 0 - data_source_set_location( - DATA_SOURCE(self), &(LocationData){ - .super.latitude = 45.215470, - .super.longitude = 5.844828, - .altitude = 718.267245 - } - ); - - data_source_set_attitude( - DATA_SOURCE(self), &(AttitudeData){ - .roll = 0, - .pitch = 0, - .heading = 43.698940 - } - ); -#endif - return self; -} - - -static bool mock_data_source_frame(MockDataSource *self, uint32_t dt) -{ - data_source_set_location( - DATA_SOURCE(self), &(LocationData){ - .super.latitude = 45.215470, - .super.longitude = 5.844828, - .altitude = 718.267245 - } - ); - - data_source_set_attitude( - DATA_SOURCE(self), &(AttitudeData){ - .roll = 0, - .pitch = 0, - .heading = 43.698940 - } - ); - - DATA_SOURCE(self)->has_fix = true; - return true; -} - - diff --git a/mock-data-source.h b/mock-data-source.h deleted file mode 100644 index 74a048b..0000000 --- a/mock-data-source.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef MOCK_DATA_SOURCE_H -#define MOCK_DATA_SOURCE_H -#include "data-source.h" - -typedef struct{ - DataSource super; -}MockDataSource; - -MockDataSource *mock_data_source_new(void); -MockDataSource *mock_data_source_init(MockDataSource *self); - -#endif /* MOCK_DATA_SOURCE_H */ diff --git a/odo-gauge.c b/odo-gauge.c deleted file mode 100644 index 89e2b6b..0000000 --- a/odo-gauge.c +++ /dev/null @@ -1,264 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include -#include -#include - -#include "base-animation.h" -#include "base-gauge.h" -#include "digit-barrel.h" -#include "odo-gauge.h" -#include "sdl-colors.h" -#include "sfv-gauge.h" - -static void odo_gauge_render(OdoGauge *self, Uint32 dt, RenderContext *ctx); -static void odo_gauge_update_state(OdoGauge *self, Uint32 dt); -static void *odo_gauge_dispose(OdoGauge *self); -static BaseGaugeOps odo_gauge_ops = { - .render = (RenderFunc)odo_gauge_render, - .update_state = (StateUpdateFunc)odo_gauge_update_state, - .dispose = (DisposeFunc)odo_gauge_dispose -}; - - -/** - * Creates a new odometer-like gauge. - * - * - * @param height height in pixels or -1 to match symbol size - * @param rubis where to place the indicator line or -1 to put it - * in the middle - * - * - */ -OdoGauge *odo_gauge_new(DigitBarrel *barrel, int height, int rubis) -{ - OdoGauge *self; - - self = calloc(1, sizeof(OdoGauge)); - if(self){ - if(!odo_gauge_init(self, rubis, 1, height, barrel)){ - return base_gauge_free(BASE_GAUGE(self)); - } - } - return self; -} - -OdoGauge *odo_gauge_new_multiple(int rubis, int nbarrels, ...) -{ - OdoGauge *self, *rv; - va_list args; - - - self = calloc(1, sizeof(OdoGauge)); - if(self){ - va_start(args, nbarrels); - rv = odo_gauge_vainit(self, rubis, nbarrels, args); - va_end(args); - if(!rv){ - return base_gauge_free(BASE_GAUGE(self)); - } - } - return self; -} - -OdoGauge *odo_gauge_vanew_multiple(int rubis, int nbarrels, va_list ap) -{ - OdoGauge *self, *rv; - - self = calloc(1, sizeof(OdoGauge)); - if(self){ - rv = odo_gauge_vainit(self, rubis, nbarrels, ap); - if(!rv){ - return base_gauge_free(BASE_GAUGE(self)); - } - } - return self; -} - - -OdoGauge *odo_gauge_init(OdoGauge *self, int rubis, int nbarrels, ...) -{ - OdoGauge *rv; - va_list args; - - va_start(args, nbarrels); - rv = odo_gauge_vainit(self, rubis, nbarrels, args); - va_end(args); - - return rv; -} - -OdoGauge *odo_gauge_vainit(OdoGauge *self, int rubis, int nbarrels, va_list ap) -{ - int width; - int max_height; - - self->nbarrels = nbarrels; - self->barrels = calloc(self->nbarrels, sizeof(DigitBarrel*)); - self->heights = calloc(self->nbarrels, sizeof(int)); - - width = 0; - max_height = 0; - for(int i = 0, pwr = 0; i < nbarrels; i++){ - self->heights[i] = va_arg(ap, int); - self->barrels[i] = va_arg(ap, DigitBarrel*); - self->barrels[i]->refcount++; - - width += generic_layer_w(GENERIC_LAYER(self->barrels[i])); - if(self->heights[i] == -1) - self->heights[i] = self->barrels[i]->symbol_h*2; - else if(self->heights[i] == -2) - self->heights[i] = self->barrels[i]->symbol_h; - max_height = (self->heights[i] > max_height) ? self->heights[i] : max_height; - - float val = floor(VERTICAL_STRIP(self->barrels[i])->end) * powf(10.0,pwr); - self->max_value += val; - pwr += number_digits(VERTICAL_STRIP(self->barrels[i])->end); - } - - self->state.barrel_states = calloc(self->nbarrels, sizeof(DigitBarrelState)); - self->state.fill_rects = calloc(self->nbarrels, sizeof(SDL_Rect)); -#if 0 - void *rv = animated_gauge_init(ANIMATED_GAUGE(self), ANIMATED_GAUGE_OPS(&odo_gauge_ops), width, max_height); -#else - /* TODO: Move me as first operation to ensure that Ops are always - * set when we return NULL so that base_gauge_dispose (called by - * base_gauge_free) can properly dispose any gauge-allocated resources*/ - void *rv = base_gauge_init(BASE_GAUGE(self), &odo_gauge_ops, width, max_height); -#endif - if(!rv){ - free(self->barrels); - return NULL; - } - if(rubis > 0) - self->rubis = rubis; - else - self->rubis = round(base_gauge_h(BASE_GAUGE(self))/2.0); - - return self; -} - -static void *odo_gauge_dispose(OdoGauge *self) -{ - for(int i = 0; i < self->nbarrels; i++){ - digit_barrel_free(self->barrels[i]); - } - free(self->barrels); - free(self->heights); - if(self->state.barrel_states) - free(self->state.barrel_states); - if(self->state.fill_rects) - free(self->state.fill_rects); - return self; -} - -bool odo_gauge_set_value(OdoGauge *self, float value, bool animated) -{ - bool rv = true; - BaseAnimation *animation; - - if(value > self->max_value){ - value = self->max_value; - rv = false; - } - - rv &= sfv_gauge_set_value(SFV_GAUGE(self), value, animated); - - return rv; -} - -static void odo_gauge_render(OdoGauge *self, Uint32 dt, RenderContext *ctx) -{ - DigitBarrelState *bstate; - for(int i = 0; i < self->state.nbarrel_states; i++){ - bstate = &self->state.barrel_states[i]; - for(int j = 0; j < bstate->npatches; j++) - base_gauge_blit_layer(BASE_GAUGE(self), ctx, bstate->layer, &bstate->patches[j].src, &bstate->patches[j].dst); - } - for(int i = 0; i < self->state.nfill_rects; i++){ - base_gauge_fill(BASE_GAUGE(self), ctx, &self->state.fill_rects[i], &SDL_BLACK, false); - } - base_gauge_draw_rubis(BASE_GAUGE(self), ctx, self->rubis, - &SDL_RED, self->state.pskip); -} - -static void odo_gauge_update_state(OdoGauge *self, Uint32 dt) -{ - float vparts[6]; /*up to 999.999 ft*/ - int nparts; - int current_part = 0; - int current_rotor = 0; - int current_rotor_rank = 0; - float current_val; - int next_part; - int i; - int rcenter; - SDL_Rect cursor; - - self->state.nbarrel_states = 0; - self->state.nfill_rects = 0; - - cursor = (SDL_Rect){ - .x = base_gauge_w(BASE_GAUGE(self)), - .y = 0, - .w = base_gauge_w(BASE_GAUGE(self)), - .h = base_gauge_h(BASE_GAUGE(self)) - }; - - /* If the buffer is shared, it's up to the "parent" - * to clear portions when appropriate - * */ -// if(BUFFERED_GAUGE(self)->type == BUFFER_OWN) -// buffered_gauge_clear(BUFFERED_GAUGE(self)); - - nparts = number_split(SFV_GAUGE(self)->value, vparts, 6); -// printf("doing value %f, splitted in to %d parts\n",value,nparts); - do{ -// current_rotor_rank = current_rotor; - current_rotor_rank += floor(log10(VERTICAL_STRIP(self->barrels[current_rotor])->end)); -// printf("current_part: %d, current_rotor_rank: %d\n",current_part,current_rotor_rank); - if(current_part == current_rotor_rank){ - current_val = vparts[current_part]; - next_part = current_part + 1; - }else{ - current_val = 0; - for(i = current_part; i <= current_rotor_rank && i < nparts ; i++) - current_val += vparts[i] * powf(10.0, i); - next_part = i; - } - cursor.x -= generic_layer_w(GENERIC_LAYER(self->barrels[current_rotor])); - cursor.h = self->heights[current_rotor]; - rcenter = (base_gauge_h(BASE_GAUGE(self))/2 - cursor.h/2); /*This is the rotor center relative to the whole gauge size*/ - cursor.y = 0 + rcenter; - cursor.w = generic_layer_w(GENERIC_LAYER(self->barrels[current_rotor])); - memset(&self->state.barrel_states[current_rotor], 0, sizeof(DigitBarrelState)); - digit_barrel_state_value(self->barrels[current_rotor], current_val, &cursor, self->rubis - rcenter, &self->state.barrel_states[current_rotor]); - self->state.nbarrel_states++; -// printf("setting rotor %d to %f\n",current_rotor, current_val); - //render that value - //next part, next rotor - current_part = next_part; - current_rotor++; - current_rotor_rank++; -// printf("current_part: %d, nparts: %d\n",current_part,nparts); - }while(current_part < nparts); - - /*Place holders for rotors that didn't render any value*/ - for(; current_rotor < self->nbarrels; current_rotor++){ - cursor.x -= generic_layer_w(GENERIC_LAYER(self->barrels[current_rotor])); - cursor.h = self->heights[current_rotor]; - cursor.y = 0 + base_gauge_h(BASE_GAUGE(self))/2 - cursor.h/2; - cursor.w = generic_layer_w(GENERIC_LAYER(self->barrels[current_rotor])); - - self->state.fill_rects[self->state.nfill_rects] = cursor; - self->state.nfill_rects++; - } - self->state.pskip = round(base_gauge_w(BASE_GAUGE(self))/2.0); -} diff --git a/odo-gauge.h b/odo-gauge.h deleted file mode 100644 index ab688ed..0000000 --- a/odo-gauge.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef ODO_GAUGE_H -#define ODO_GAUGE_H - -#include -#include - -#include "sfv-gauge.h" -#include "digit-barrel.h" - - -typedef struct{ - DigitBarrelState *barrel_states; - uintf8_t nbarrel_states; /*Must be the same type as OdoGauge::nbarrels*/ - - SDL_Rect *fill_rects; - uintf8_t nfill_rects; /*Must be the same type as OdoGauge::nbarrels*/ - - int pskip; -}OdoGaugeState; - -typedef struct{ - SfvGauge super; - - DigitBarrel **barrels; - int *heights; - uintf8_t nbarrels; - - int rubis; - float max_value; - - OdoGaugeState state; -}OdoGauge; - -OdoGauge *odo_gauge_new(DigitBarrel *barrel, int height, int rubis); -OdoGauge *odo_gauge_new_multiple(int rubis, int nbarrels, ...); -OdoGauge *odo_gauge_vanew_multiple(int rubis, int nbarrels, va_list ap); -OdoGauge *odo_gauge_init(OdoGauge *self, int rubis, int nbarrels, ...); -OdoGauge *odo_gauge_vainit(OdoGauge *self, int rubis, int nbarrels, va_list ap); - -bool odo_gauge_set_value(OdoGauge *self, float value, bool animated); -#endif /* ODO_GAUGE_H */ diff --git a/res-dirs.h b/res-dirs.h deleted file mode 100644 index 2b5fc17..0000000 --- a/res-dirs.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef RES_DIRS_H -#define RES_DIRS_H - -#ifndef SFS_HOME -#define SFS_HOME "." -#endif - - -#ifndef IMG_DIR -#define IMG_DIR SFS_HOME"/resources/gauges" -#endif - -#ifndef FONT_DIR -#define FONT_DIR SFS_HOME"/resources/fonts" -#endif - -#ifndef MAPS_HOME -#define MAPS_HOME SFS_HOME"/resources/maps" -#endif - -#endif /* RES_DIRS_H */ diff --git a/resource-manager.c b/resource-manager.c deleted file mode 100644 index 066a5cf..0000000 --- a/resource-manager.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include -#include - -#include "SDL_pixels.h" -#include "SDL_pcf.h" - -#include "resource-manager.h" -#include "misc.h" -#include - -static ResourceManager *_instance = NULL; -static void resource_manager_push_static_font(PCF_StaticFont *font, FontResource creator); - -static ResourceManager *resource_manager_new(void) -{ - ResourceManager *self; - - self = calloc(1, sizeof(ResourceManager)); - if(self){ - /*init as needed*/ - } - return self; -} - -static inline ResourceManager *resource_manager_get_instance(void) -{ - if(!_instance) - _instance = resource_manager_new(); - return _instance; -} - -void resource_manager_shutdown(void) -{ - ResourceManager *self; - - self = _instance; - if(!self) return; - - for(int i = 0; i < FONT_MAX; i++){ - if(self->fonts[i]){ - if(self->fonts[i]->xfont.refcnt > 1){ - printf( - "ResourceManager: Font %d refcount was still %d at shutdown (1 expected), leaking %p\n", - i, - self->fonts[i]->xfont.refcnt, - self->fonts[i] - ); - } - PCF_FontUnref(self->fonts[i]); - PCF_CloseFont(self->fonts[i]); - } - } - - for(int i = 0; i < self->n_sfonts; i++){ - if(self->sfonts[i].font->refcnt > 1){ - printf( - "ResourceManager: StaticFont %d refcount was still %d at shutdown (1 expected), leaking %p\n", - i, - self->sfonts[i].font->refcnt, - self->sfonts[i].font - ); - } - PCF_StaticFontUnref(self->sfonts[i].font); - PCF_FreeStaticFont(self->sfonts[i].font); - } - if(self->sfonts) - free(self->sfonts); - free(self); - _instance = NULL; -} - -static const char *resource_manager_get_font_filename(FontResource font) -{ - switch (font) { - case TERMINUS_12: - return FONT_DIR"/ter-x12n.pcf.gz"; - case TERMINUS_14: - return FONT_DIR"/ter-x14n.pcf.gz"; - case TERMINUS_16: - return FONT_DIR"/ter-x16n.pcf.gz"; - case TERMINUS_18: - return FONT_DIR"/ter-x18n.pcf.gz"; - case TERMINUS_20: - return FONT_DIR"/ter-x20n.pcf.gz"; - case TERMINUS_22: - return FONT_DIR"/ter-x22n.pcf.gz"; - case TERMINUS_24: - return FONT_DIR"/ter-x24n.pcf.gz"; - case TERMINUS_28: - return FONT_DIR"/ter-x28n.pcf.gz"; - case TERMINUS_32: - return FONT_DIR"/ter-x32n.pcf.gz"; - case FONT_MAX: - default: - return NULL; - } -} - -PCF_Font *resource_manager_get_font(FontResource font) -{ - ResourceManager *self; - - self = resource_manager_get_instance(); - if(!self->fonts[font]){ - self->fonts[font] = PCF_OpenFont(resource_manager_get_font_filename(font)); - if(self->fonts[font]) - PCF_FontRef(self->fonts[font]); - } - return self->fonts[font]; -} - -PCF_StaticFont *resource_manager_get_static_font(FontResource font, SDL_Color *color, int nsets, ...) -{ - char *str; - size_t tlen; - va_list ap; - ResourceManager *self; - PCF_StaticFont *rv; - - self = resource_manager_get_instance(); - - - tlen = 0; - va_start(ap, nsets); - for(int i = 0; i < nsets; i++){ - tlen += strlen(va_arg(ap, char*)); - } - va_end(ap); - - str = malloc((tlen + 1) * sizeof(char)); - if(!str) return NULL; - - char *iter = str; - va_start(ap, nsets); - for(int i = 0; i < nsets; i++){ - char *tmp = va_arg(ap, char*); - strcpy(iter, tmp); - iter += strlen(tmp)*sizeof(char); - } - va_end(ap); - - qsort(str, strlen(str), sizeof(char), charcmp); - filter_dedup(str, tlen); -// printf("ResourceManager: looking for a (r:%d,g:%d,b:%d,a:%d) font of type %d with the following charset: %s\n",color->r,color->g,color->b,color->a, font, str); - for(int i = 0; i < self->n_sfonts; i++){ - if(self->sfonts[i].creator != font) continue; - if(PCF_StaticFontCanWrite(self->sfonts[i].font, color, str)){ -// printf("Found existing instance %p(glyphs: %s)\n", self->sfonts[i].font, self->sfonts[i].font->glyphs); - rv = self->sfonts[i].font; - goto end; - } - } - - va_start(ap, nsets); - rv = PCF_FontCreateStaticFontVA( - resource_manager_get_font(font), - color, - nsets, - tlen, ap - ); - va_end(ap); - resource_manager_push_static_font(rv, font); -// printf("Not found, created a new one: %p(glyphs: %s)\n", rv, rv->glyphs); - -end: - free(str); - return rv; -} - -static void resource_manager_push_static_font(PCF_StaticFont *font, FontResource creator) -{ - ResourceManager *self; - - self = resource_manager_get_instance(); - if(self->n_sfonts == self->n_allocated){ - StaticFontResource *tmp; - tmp = realloc(self->sfonts, (self->n_allocated + 4) * sizeof(StaticFontResource)); - if(!tmp) - return; //TODO: OOM / Check leaks - self->sfonts = tmp; - self->n_allocated += 4; - } - self->sfonts[self->n_sfonts].font = font; - self->sfonts[self->n_sfonts].creator = creator; - self->n_sfonts++; - PCF_StaticFontRef(font); -} diff --git a/resource-manager.h b/resource-manager.h deleted file mode 100644 index 4c71b6b..0000000 --- a/resource-manager.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef RESOURCE_MANAGER_H -#define RESOURCE_MANAGER_H - -#include "SDL_pcf.h" - - -typedef enum{ - TERMINUS_12, - TERMINUS_14, - TERMINUS_16, - TERMINUS_18, - TERMINUS_20, - TERMINUS_22, - TERMINUS_24, - TERMINUS_28, - TERMINUS_32, - - FONT_MAX -}FontResource; - -typedef struct{ - PCF_StaticFont *font; - SDL_Color color; - FontResource creator; -}StaticFontResource; - -typedef struct{ - PCF_Font *fonts[FONT_MAX]; - - StaticFontResource *sfonts; - size_t n_allocated; - size_t n_sfonts; -}ResourceManager; - -PCF_Font *resource_manager_get_font(FontResource font); -PCF_StaticFont *resource_manager_get_static_font(FontResource font, SDL_Color *color, int nsets, ...); - -void resource_manager_shutdown(void); -#endif /* RESOURCE_MANAGER_H */ diff --git a/resources/fonts/ter-x12n.pcf.gz b/resources/fonts/ter-x12n.pcf.gz deleted file mode 100644 index 62f7073..0000000 Binary files a/resources/fonts/ter-x12n.pcf.gz and /dev/null differ diff --git a/resources/fonts/ter-x14n.pcf.gz b/resources/fonts/ter-x14n.pcf.gz deleted file mode 100644 index d89e413..0000000 Binary files a/resources/fonts/ter-x14n.pcf.gz and /dev/null differ diff --git a/resources/fonts/ter-x16n.pcf.gz b/resources/fonts/ter-x16n.pcf.gz deleted file mode 100644 index f6d0c7f..0000000 Binary files a/resources/fonts/ter-x16n.pcf.gz and /dev/null differ diff --git a/resources/fonts/ter-x18n.pcf.gz b/resources/fonts/ter-x18n.pcf.gz deleted file mode 100644 index a828c60..0000000 Binary files a/resources/fonts/ter-x18n.pcf.gz and /dev/null differ diff --git a/resources/fonts/ter-x20n.pcf.gz b/resources/fonts/ter-x20n.pcf.gz deleted file mode 100644 index c969f30..0000000 Binary files a/resources/fonts/ter-x20n.pcf.gz and /dev/null differ diff --git a/resources/fonts/ter-x22n.pcf.gz b/resources/fonts/ter-x22n.pcf.gz deleted file mode 100644 index e7d50d4..0000000 Binary files a/resources/fonts/ter-x22n.pcf.gz and /dev/null differ diff --git a/resources/fonts/ter-x24n.pcf.gz b/resources/fonts/ter-x24n.pcf.gz deleted file mode 100644 index acd0ec8..0000000 Binary files a/resources/fonts/ter-x24n.pcf.gz and /dev/null differ diff --git a/resources/fonts/ter-x28n.pcf.gz b/resources/fonts/ter-x28n.pcf.gz deleted file mode 100644 index c696ba4..0000000 Binary files a/resources/fonts/ter-x28n.pcf.gz and /dev/null differ diff --git a/resources/fonts/ter-x32n.pcf.gz b/resources/fonts/ter-x32n.pcf.gz deleted file mode 100644 index 3952435..0000000 Binary files a/resources/fonts/ter-x32n.pcf.gz and /dev/null differ diff --git a/resources/gauges/alt-ladder.png b/resources/gauges/alt-ladder.png deleted file mode 100644 index 4ab497d..0000000 Binary files a/resources/gauges/alt-ladder.png and /dev/null differ diff --git a/resources/gauges/center-marker.png b/resources/gauges/center-marker.png deleted file mode 100644 index 7b44f3a..0000000 Binary files a/resources/gauges/center-marker.png and /dev/null differ diff --git a/resources/gauges/compass-inner.png b/resources/gauges/compass-inner.png deleted file mode 100644 index 64e4a39..0000000 Binary files a/resources/gauges/compass-inner.png and /dev/null differ diff --git a/resources/gauges/compass-outer.png b/resources/gauges/compass-outer.png deleted file mode 100644 index 77e649d..0000000 Binary files a/resources/gauges/compass-outer.png and /dev/null differ diff --git a/resources/gauges/fishbone-cursor.png b/resources/gauges/fishbone-cursor.png deleted file mode 100644 index 7b72a80..0000000 Binary files a/resources/gauges/fishbone-cursor.png and /dev/null differ diff --git a/resources/gauges/horizon-grads-scaled.png b/resources/gauges/horizon-grads-scaled.png deleted file mode 100644 index c49ccb1..0000000 Binary files a/resources/gauges/horizon-grads-scaled.png and /dev/null differ diff --git a/resources/gauges/left-marker.png b/resources/gauges/left-marker.png deleted file mode 100644 index 4a2e3da..0000000 Binary files a/resources/gauges/left-marker.png and /dev/null differ diff --git a/resources/gauges/lh-cursor10.png b/resources/gauges/lh-cursor10.png deleted file mode 100644 index 4cc1fd8..0000000 Binary files a/resources/gauges/lh-cursor10.png and /dev/null differ diff --git a/resources/gauges/plane32.png b/resources/gauges/plane32.png deleted file mode 100644 index 10f1f33..0000000 Binary files a/resources/gauges/plane32.png and /dev/null differ diff --git a/resources/gauges/rh-cursor10.png b/resources/gauges/rh-cursor10.png deleted file mode 100644 index 743bb13..0000000 Binary files a/resources/gauges/rh-cursor10.png and /dev/null differ diff --git a/resources/gauges/right-marker.png b/resources/gauges/right-marker.png deleted file mode 100644 index eb6de6e..0000000 Binary files a/resources/gauges/right-marker.png and /dev/null differ diff --git a/resources/gauges/roll-arc.png b/resources/gauges/roll-arc.png deleted file mode 100644 index 90701f4..0000000 Binary files a/resources/gauges/roll-arc.png and /dev/null differ diff --git a/resources/gauges/roll-marker.png b/resources/gauges/roll-marker.png deleted file mode 100644 index 0fbdc43..0000000 Binary files a/resources/gauges/roll-marker.png and /dev/null differ diff --git a/resources/gauges/slip-marker.png b/resources/gauges/slip-marker.png deleted file mode 100644 index b21dcc5..0000000 Binary files a/resources/gauges/slip-marker.png and /dev/null differ diff --git a/resources/gauges/speed-ladder.png b/resources/gauges/speed-ladder.png deleted file mode 100644 index 8084fb1..0000000 Binary files a/resources/gauges/speed-ladder.png and /dev/null differ diff --git a/resources/maps/.gitignore b/resources/maps/.gitignore deleted file mode 100644 index f14b80c..0000000 --- a/resources/maps/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -# Ignore everything in this directory -/* -!.gitignore - -!/osm/ -/osm/* -!/osm/map.conf - -!/openaip/ -/openaip/* -!/openaip/map.conf diff --git a/resources/maps/openaip/map.conf b/resources/maps/openaip/map.conf deleted file mode 100644 index 4016983..0000000 --- a/resources/maps/openaip/map.conf +++ /dev/null @@ -1,6 +0,0 @@ -#Covered area by level, in tile coordinates -# area: level left right top bottom -# no area: line means whole earth -# -#If a tile is missing, how to fetch it -src: https://api.tiles.openaip.net/api/data/openaip/%LEVEL%/%TILE_X%/%TILE_Y%.png?apiKey=YOUR-API-KEY diff --git a/resources/maps/osm/map.conf b/resources/maps/osm/map.conf deleted file mode 100644 index 9367008..0000000 --- a/resources/maps/osm/map.conf +++ /dev/null @@ -1,6 +0,0 @@ -#Covered area by level, in tile coordinates -# area: level left right top bottom -# no area: line means whole earth -# -#If a tile is missing, how to fetch it -src: https://tile.openstreetmap.org/%LEVEL%/%TILE_X%/%TILE_Y%.png diff --git a/roll-slip-gauge.c b/roll-slip-gauge.c deleted file mode 100644 index b748593..0000000 --- a/roll-slip-gauge.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include - -#include -#include - -#include "roll-slip-gauge.h" -#include "misc.h" -#include "res-dirs.h" - -#define sign(x) (((x) > 0) - ((x) < 0)) - -static void roll_slip_gauge_render(RollSlipGauge *self, Uint32 dt, RenderContext *ctx); -static void roll_slip_gauge_update_state(RollSlipGauge *self, Uint32 dt); -static RollSlipGauge *roll_slip_gauge_dispose(RollSlipGauge *self); -static BaseGaugeOps roll_slip_gauge_ops = { - .render = (RenderFunc)roll_slip_gauge_render, - .update_state = (StateUpdateFunc)roll_slip_gauge_update_state, - .dispose = (DisposeFunc)roll_slip_gauge_dispose -}; - - -RollSlipGauge *roll_slip_gauge_new(void) -{ - RollSlipGauge *self; - - self = calloc(1, sizeof(RollSlipGauge)); - if(self){ - if(!roll_slip_gauge_init(self)){ - return base_gauge_free(BASE_GAUGE(self)); - } - } - return self; -} - -RollSlipGauge *roll_slip_gauge_init(RollSlipGauge *self) -{ - base_gauge_init(BASE_GAUGE(self), &roll_slip_gauge_ops, 183, 183); - - generic_layer_init_from_file(&self->arc, IMG_DIR"/roll-arc.png"); - if(!self->arc.canvas) return NULL; - generic_layer_build_texture(&self->arc); - - generic_layer_init_from_file(&self->marker, IMG_DIR"/roll-marker.png"); - if(!self->marker.canvas) return NULL; - generic_layer_build_texture(&self->marker); - - generic_layer_init_from_file(&self->slip_marker, IMG_DIR"/slip-marker.png"); - if(!self->slip_marker.canvas) return NULL; - generic_layer_build_texture(&self->slip_marker); - - - //TODO: Center on with surfaces, generic_layer_midX, base_gauge_midx -// self->marker_rect.x = (base_gauge_w(BASE_GAUGE(self))/2) - tmp->w/2; //TODO Middle function that handle even/odd -// printf("self->marker_rect.x: %d\n",self->marker_rect.x); - self->marker_rect.x = 91 - 4; - self->marker_rect.y = 11; - self->marker_rect.w = generic_layer_w(&self->marker); - self->marker_rect.h = generic_layer_h(&self->marker); - - self->state.slip_rect.x = SDLExt_RectMidX(&self->marker_rect) - generic_layer_w(&self->slip_marker)/2; - self->state.slip_rect.y = SDLExt_RectLastY(&self->marker_rect) + 2; - self->state.slip_rect.w = generic_layer_w(&self->slip_marker); - self->state.slip_rect.h = generic_layer_h(&self->slip_marker); - -#if !USE_SDL_GPU - self->state.rbuffer = SDL_CreateRGBSurfaceWithFormat(0, - base_gauge_w(BASE_GAUGE(self)), - base_gauge_h(BASE_GAUGE(self)), - 32, SDL_PIXELFORMAT_RGBA32 - ); - self->renderer = SDL_CreateSoftwareRenderer(self->state.rbuffer); - self->arc_texture = SDL_CreateTextureFromSurface(self->renderer, tmp); -#endif - - return self; -} - -static RollSlipGauge *roll_slip_gauge_dispose(RollSlipGauge *self) -{ - generic_layer_dispose(&self->arc); - generic_layer_dispose(&self->marker); - generic_layer_dispose(&self->slip_marker); -#if !USE_SDL_GPU - if(self->state.rbuffer) - SDL_FreeSurface(self->state.rbuffer); - SDL_DestroyRenderer(self->renderer); /*Will also free self->arrow*/ -#endif - - return self; -} - -bool roll_slip_gauge_set_value(RollSlipGauge *self, float value, bool animated) -{ - bool rv = true; - BaseAnimation *animation; - animated = false; - if(value > 60.0 || value < -60.0) - value = sign(value)*65; - - return sfv_gauge_set_value(SFV_GAUGE(self), value, animated); -} - -bool roll_slip_gauge_set_slip(RollSlipGauge *self, float value, bool animated) -{ - bool rv = true; - BaseAnimation *animation; - animated = false; - - if(fabsf(value) > 90.0) - return false; - - self->slip = value; - BASE_GAUGE(self)->dirty = true; - - return true; -} - - -static void roll_slip_gauge_update_state(RollSlipGauge *self, Uint32 dt) -{ - float ratio = self->slip/90.0; - - int base_x = SDLExt_RectMidX(&self->marker_rect) - generic_layer_w(&self->slip_marker)/2; - int increment = roundf(ratio * (self->marker_rect.w)); - - self->state.slip_rect.x = base_x + increment; -#if !USE_SDL_GPU - SDL_FillRect(self->state.rbuffer, NULL, 0x00000000); - SDL_RenderCopyEx(self->renderer, - self->arc_texture, - NULL, /*Whole texture*/ - NULL, /*Whole surface*/ - -SFV_GAUGE(self)->value, - NULL, /*Rotate on center*/ - SDL_FLIP_NONE); -#endif -} - -static void roll_slip_gauge_render(RollSlipGauge *self, Uint32 dt, RenderContext *ctx) -{ - base_gauge_blit_layer(BASE_GAUGE(self), ctx, - &self->marker, NULL, - &self->marker_rect - ); - - base_gauge_blit_layer(BASE_GAUGE(self), ctx, - &self->slip_marker, NULL, - &self->state.slip_rect - ); - -#if USE_SDL_GPU - base_gauge_blit_rotated_texture(BASE_GAUGE(self), ctx, - self->arc.texture, - NULL, - -SFV_GAUGE(self)->value, - NULL, /*rotate on center*/ - NULL, /*Whole gauge*/ - NULL); -#else - base_gauge_blit(BASE_GAUGE(self), ctx, self->state.rbuffer, NULL, NULL); -#endif -} diff --git a/roll-slip-gauge.h b/roll-slip-gauge.h deleted file mode 100644 index a4f4baf..0000000 --- a/roll-slip-gauge.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef ROLL_SLIP_GAUGE_H -#define ROLL_SLIP_GAUGE_H - -#include - -#include "sfv-gauge.h" -#include "generic-layer.h" - -typedef struct{ - SDL_Rect slip_rect; -#if !USE_SDL_GPU - SDL_Surface *rbuffer; /*rotation buffer*/ -#endif -}RollSlipGaugeState; - -typedef struct{ - SfvGauge super; - float slip; - - GenericLayer arc; - GenericLayer marker; - GenericLayer slip_marker; - -#if !USE_SDL_GPU - SDL_Texture *arc_texture; - SDL_Renderer *renderer; -#endif - SDL_Rect marker_rect; - - RollSlipGaugeState state; -}RollSlipGauge; - - -RollSlipGauge *roll_slip_gauge_new(void); -RollSlipGauge *roll_slip_gauge_init(RollSlipGauge *self); - -bool roll_slip_gauge_set_value(RollSlipGauge *self, float value, bool animated); -bool roll_slip_gauge_set_slip(RollSlipGauge *self, float value, bool animated); -#endif /* ROLL_SLIP_GAUGE_H */ diff --git a/route-map-provider.c b/route-map-provider.c deleted file mode 100644 index 7eb9824..0000000 --- a/route-map-provider.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include - -#include "generic-layer.h" -#include "route-map-provider.h" -#include "geo-location.h" -#include "map-provider.h" -#include "misc.h" -#include "map-math.h" -#include "sdl-colors.h" - -/*Line drawing adapted from https://github.com/miloyip/line*/ -static float capsuleSDF(float px, float py, float ax, float ay, float bx, float by, float r); -static void line_portion(GenericLayer *layer, int tx, int ty, - SDL_Point world_from, - SDL_Point world_to, - int r, - SDL_Color color); -static inline void alphablend(GenericLayer *layer, int x, int y, - Uint8 alpha, Uint8 r, Uint8 g, Uint8 b); - -static GenericLayer *route_map_provider_get_tile(RouteMapProvider *self, - uintf8_t level, - int32_t x, int32_t y); - -static MapProviderOps route_map_provider_ops = { - .get_tile = (MapProviderGetTileFunc)route_map_provider_get_tile, - .dispose = NULL -}; - -RouteMapProvider *route_map_provider_new(void) -{ - RouteMapProvider *self; - - self = calloc(1, sizeof(RouteMapProvider)); - if(self){ - if(!route_map_provider_init(self)) - return (RouteMapProvider*)map_provider_free(MAP_PROVIDER(self)); - } - return self; -} - -RouteMapProvider *route_map_provider_init(RouteMapProvider *self) -{ - map_provider_init(MAP_PROVIDER(self), &route_map_provider_ops, 10); - map_provider_set_nareas(MAP_PROVIDER(self), 1); /*TODO: Inefficient*/ - self->current_zoom = -1; - self->geo_from.latitude = NAN; - return self; -} - -bool route_map_provider_set_route(RouteMapProvider *self, - GeoLocation *from, - GeoLocation *to) -{ - self->geo_from = *from; - self->geo_to = *to; - self->current_zoom = -1; - - return true; -} - -static bool route_map_provider_set_level(RouteMapProvider *self, uintf8_t level) -{ - self->current_zoom = level; - - map_math_geo_to_pixel( - self->geo_from.latitude, self->geo_from.longitude, - level, &self->from.x, &self->from.y - ); - map_math_geo_to_pixel( - self->geo_to.latitude, self->geo_to.longitude, - level, &self->to.x, &self->to.y - ); - MAP_PROVIDER(self)->areas[0] = (MapProviderArea){ - .top = MIN(self->from.y, self->to.y)/256, - .left = MIN(self->from.x, self->to.x)/256, - .bottom = MAX(self->from.y, self->to.y)/256, - .right = MAX(self->from.x, self->to.x)/256, - .level = level - }; - - return true; -} - -static GenericLayer *route_map_provider_get_tile(RouteMapProvider *self, - uintf8_t level, - int32_t x, int32_t y) -{ - GenericLayer *rv = NULL; - - if(isnan(self->geo_from.latitude)) return NULL; - - if(self->current_zoom != level) - route_map_provider_set_level(self, level); - - if(MAP_PROVIDER(self)->nareas && !map_provider_has_tile(MAP_PROVIDER(self), level, x, y)) - return NULL; - - rv = generic_layer_new(256, 256); - - line_portion(rv, x, y, self->from, self->to, 2, SDL_RED); - - return rv; -} - -static float capsuleSDF(float px, float py, float ax, float ay, float bx, float by, float r) -{ - float pax = px - ax, pay = py - ay, bax = bx - ax, bay = by - ay; - float h = fmaxf(fminf((pax * bax + pay * bay) / (bax * bax + bay * bay), 1.0f), 0.0f); - float dx = pax - bax * h, dy = pay - bay * h; - return sqrtf(dx * dx + dy * dy) - r; -} - -static inline void alphablend(GenericLayer *layer, int x, int y, - Uint8 alpha, Uint8 r, Uint8 g, Uint8 b) -{ - SDL_Surface *output = layer->canvas; - - if(x < 0 || y < 0 || x > output->w-1 || y > output->h-1 ){ - return; - } - uint8_t *p = (Uint8*)output->pixels - + (y * output->pitch) - + (x * output->format->BytesPerPixel); - p[0] = r; - p[1] = g; - p[2] = b; - p[3] = alpha; -} - -static void line_portion(GenericLayer *layer, int tx, int ty, - SDL_Point world_from, - SDL_Point world_to, - int r, - SDL_Color color) -{ - /*Tile 0: 0 -> 255 Tile 1: 256 -> 511*/ - int ax = tx * 256; - int bx = ax + 256 - 1; - int ay = ty * 256; - int by = ay + 256 - 1; - - int x0 = MIN(ax, bx) - r; - int x1 = MAX(ax, bx) + r; - int y0 = MIN(ay, by) - r; - int y1 = MAX(ay, by) + r; - - generic_layer_lock(layer); - for (int y = y0; y <= y1; y++){ - for (int x = x0; x <= x1; x++){ - float alpha =fmaxf( - fminf(0.5f - capsuleSDF( - x, - y, - world_from.x, world_from.y, - world_to.x, world_to.y, - r - ), - 1.0f - ), - 0.0f - ); - - alphablend(layer, - x - tx * 256, - y - ty * 256, - (Uint8)(alpha * 255), - color.r, color.g, color.b - ); - } - } - generic_layer_unlock(layer); -} - diff --git a/route-map-provider.h b/route-map-provider.h deleted file mode 100644 index a83f32f..0000000 --- a/route-map-provider.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef ROUTE_MAP_PROVIDER_H -#define ROUTE_MAP_PROVIDER_H -#include "geo-location.h" -#include "map-provider.h" -#include "misc.h" - -typedef struct{ - MapProvider super; - - /*Lat/lon*/ - GeoLocation geo_from; - GeoLocation geo_to; - - intf8_t current_zoom; - SDL_Point from; - SDL_Point to; -}RouteMapProvider; - -RouteMapProvider *route_map_provider_new(void); -RouteMapProvider *route_map_provider_init(RouteMapProvider *self); - -bool route_map_provider_set_route(RouteMapProvider *self, - GeoLocation *from, - GeoLocation *to); - -#endif /* ROUTE_MAP_PROVIDER_H */ diff --git a/scripts/geolocation.py b/scripts/geolocation.py deleted file mode 100644 index bb665cd..0000000 --- a/scripts/geolocation.py +++ /dev/null @@ -1,143 +0,0 @@ -# https://github.com/jfein/PyGeoTools/blob/master/geolocation.py -import math - - -class GeoLocation: - ''' - Class representing a coordinate on a sphere, most likely Earth. - - This class is based from the code smaple in this paper: - http://janmatuschek.de/LatitudeLongitudeBoundingCoordinates - - The owner of that website, Jan Philip Matuschek, is the full owner of - his intellectual property. This class is simply a Python port of his very - useful Java code. All code written by Jan Philip Matuschek and ported by me - (github user jfein) (which is all of this class) is owned - by Jan Philip Matuschek. - ''' - - - MIN_LAT = math.radians(-90) - MAX_LAT = math.radians(90) - MIN_LON = math.radians(-180) - MAX_LON = math.radians(180) - - EARTH_RADIUS = 6378.1 # kilometers - - - @classmethod - def from_degrees(cls, deg_lat, deg_lon): - rad_lat = math.radians(deg_lat) - rad_lon = math.radians(deg_lon) - return GeoLocation(rad_lat, rad_lon, deg_lat, deg_lon) - - @classmethod - def from_radians(cls, rad_lat, rad_lon): - deg_lat = math.degrees(rad_lat) - deg_lon = math.degrees(rad_lon) - return GeoLocation(rad_lat, rad_lon, deg_lat, deg_lon) - - - def __init__( - self, - rad_lat, - rad_lon, - deg_lat, - deg_lon - ): - self.rad_lat = float(rad_lat) - self.rad_lon = float(rad_lon) - self.deg_lat = float(deg_lat) - self.deg_lon = float(deg_lon) - self._check_bounds() - - def __str__(self): - degree_sign= u'\N{DEGREE SIGN}' - return ("({0:.4f}deg, {1:.4f}deg) = ({2:.6f}rad, {3:.6f}rad)").format( - self.deg_lat, self.deg_lon, self.rad_lat, self.rad_lon) - - def _check_bounds(self): - if (self.rad_lat < GeoLocation.MIN_LAT - or self.rad_lat > GeoLocation.MAX_LAT - or self.rad_lon < GeoLocation.MIN_LON - or self.rad_lon > GeoLocation.MAX_LON): - raise Exception("Illegal arguments") - - def distance_to(self, other, radius=EARTH_RADIUS): - ''' - Computes the great circle distance between this GeoLocation instance - and the other. - ''' - return radius * math.acos( - math.sin(self.rad_lat) * math.sin(other.rad_lat) + - math.cos(self.rad_lat) * - math.cos(other.rad_lat) * - math.cos(self.rad_lon - other.rad_lon) - ) - - def bounding_locations(self, distance, radius=EARTH_RADIUS): - ''' - Computes the bounding coordinates of all points on the surface - of a sphere that has a great circle distance to the point represented - by this GeoLocation instance that is less or equal to the distance argument. - - Param: - distance - the distance from the point represented by this GeoLocation - instance. Must be measured in the same unit as the radius - argument (which is kilometers by default) - - radius - the radius of the sphere. defaults to Earth's radius. - - Returns a list of two GeoLoations - the SW corner and the NE corner - that - represents the bounding box. - ''' - - if radius < 0 or distance < 0: - raise Exception("Illegal arguments") - - # angular distance in radians on a great circle - rad_dist = distance / radius - - min_lat = self.rad_lat - rad_dist - max_lat = self.rad_lat + rad_dist - - if min_lat > GeoLocation.MIN_LAT and max_lat < GeoLocation.MAX_LAT: - delta_lon = math.asin(math.sin(rad_dist) / math.cos(self.rad_lat)) - - min_lon = self.rad_lon - delta_lon - if min_lon < GeoLocation.MIN_LON: - min_lon += 2 * math.pi - - max_lon = self.rad_lon + delta_lon - if max_lon > GeoLocation.MAX_LON: - max_lon -= 2 * math.pi - # a pole is within the distance - else: - min_lat = max(min_lat, GeoLocation.MIN_LAT) - max_lat = min(max_lat, GeoLocation.MAX_LAT) - min_lon = GeoLocation.MIN_LON - max_lon = GeoLocation.MAX_LON - - return [ GeoLocation.from_radians(min_lat, min_lon) , - GeoLocation.from_radians(max_lat, max_lon) ] - - - -if __name__ == '__main__': - # Test degree to radian conversion - loc1 = GeoLocation.from_degrees(26.062951, -80.238853) - loc2 = GeoLocation.from_radians(loc1.rad_lat, loc1.rad_lon) - assert (loc1.rad_lat == loc2.rad_lat and loc1.rad_lon == loc2.rad_lon - and loc1.deg_lat == loc2.deg_lat and loc1.deg_lon == loc2.deg_lon) - - # Test distance between two locations - loc1 = GeoLocation.from_degrees(26.062951, -80.238853) - loc2 = GeoLocation.from_degrees(26.060484,-80.207268) - assert loc1.distance_to(loc2) == loc2.distance_to(loc1) - - # Test bounding box - loc = GeoLocation.from_degrees(26.062951, -80.238853) - distance = 1 # 1 kilometer - SW_loc, NE_loc = loc.bounding_locations(distance) - print(loc.distance_to(SW_loc)) - print(loc.distance_to(NE_loc)) diff --git a/scripts/precache-openaip.py b/scripts/precache-openaip.py deleted file mode 100755 index 961b567..0000000 --- a/scripts/precache-openaip.py +++ /dev/null @@ -1,302 +0,0 @@ -#! /usr/bin/python -# SPDX-FileCopyrightText: 2021 Samuel Cuella -# -# This file is part of SoFIS - an open source EFIS -# -# SPDX-License-Identifier: GPL-2.0-only - -import argparse -from geolocation import * -import shutil -import math -import subprocess -import os - -MIN_LAT=-85.05112878 -MAX_LAT=85.05112878 -MIN_LON=-180 -MAX_LON=180 - -PROVIDERS=[ - {'url':"https://tile.openstreetmap.org/%d/%d/%d.png", - 'hosts':[]}, - {'url':"https://%s.tile.maps.openaip.net/geowebcache/service/tms/1.0.0/openaip_basemap@EPSG%%3A900913@png/%d/%d/%d.png", - 'hosts':['1','2'], - 'mode':'tms'}, - {'url':"https://%s.tile.maps.openaip.net/geowebcache/service/tms/1.0.0/openaip_approved_airports@EPSG%%3A900913@png/%d/%d/%d.png", - 'hosts':['1','2'], - 'mode':'tms'} -] - -STATES={ - 'AL':{'name':'Alabama','north':35.008028,'east':-84.889080,'south':30.223334,'west':-88.473227}, - 'AK':{'name':'Alaska','north':71.365162,'east':179.778470,'south':51.214183,'west':-179.148909}, - 'AS':{'name':'American Samoa','north':-11.046934,'east':-168.143300,'south':-14.548699,'west':-171.089874}, - 'AZ':{'name':'Arizona','north':37.004260,'east':-109.045223,'south':31.332177,'west':-114.816510}, - 'AR':{'name':'Arkansas','north':36.499600,'east':-89.644395,'south':33.004106,'west':-94.617919}, - 'CA':{'name':'California','north':42.009518,'east':-114.131211,'south':32.534156,'west':-124.409591}, - 'CO':{'name':'Colorado','north':41.003444,'east':-102.041524,'south':36.992426,'west':-109.060253}, - 'MP':{'name':'Commonwealth of the Northern Mariana Islands','north':20.553802,'east':146.064818,'south':14.110472,'west':144.886331}, - 'CT':{'name':'Connecticut','north':42.050587,'east':-71.786994,'south':40.980144,'west':-73.727775}, - 'DE':{'name':'Delaware','north':39.839007,'east':-75.048939,'south':38.451013,'west':-75.788658}, - 'DC':{'name':'District of Columbia','north':38.995110,'east':-76.909395,'south':38.791645,'west':-77.119759}, - 'FL':{'name':'Florida','north':31.000888,'east':-80.031362,'south':24.523096,'west':-87.634938}, - 'GA':{'name':'Georgia','north':35.000659,'east':-80.839729,'south':30.357851,'west':-85.605165}, - 'GU':{'name':'Guam','north':13.654383,'east':144.956712,'south':13.234189,'west':144.618068}, - 'HI':{'name':'Hawaii','north':28.402123,'east':-154.806773,'south':18.910361,'west':-178.334698}, - 'ID':{'name':'Idaho','north':49.001146,'east':-111.043564,'south':41.988057,'west':-117.243027}, - 'IL':{'name':'Illinois','north':42.508481,'east':-87.494756,'south':36.970298,'west':-91.513079}, - 'IN':{'name':'Indiana','north':41.760592,'east':-84.784579,'south':37.771742,'west':-88.097760}, - 'IA':{'name':'Iowa','north':43.501196,'east':-90.140061,'south':40.375501,'west':-96.639704}, - 'KS':{'name':'Kansas','north':40.003162,'east':-94.588413,'south':36.993016,'west':-102.051744}, - 'KY':{'name':'Kentucky','north':39.147458,'east':-81.964971,'south':36.497129,'west':-89.571509}, - 'LA':{'name':'Louisiana','north':33.019457,'east':-88.817017,'south':28.928609,'west':-94.043147}, - 'ME':{'name':'Maine','north':47.459686,'east':-66.949895,'south':42.977764,'west':-71.083924}, - 'MD':{'name':'Maryland','north':39.723043,'east':-75.048939,'south':37.911717,'west':-79.487651}, - 'MA':{'name':'Massachusetts','north':42.886589,'east':-69.928393,'south':41.237964,'west':-73.508142}, - 'MI':{'name':'Michigan','north':48.238800,'east':-82.413474,'south':41.696118,'west':-90.418136}, - 'MN':{'name':'Minnesota','north':49.384358,'east':-89.491739,'south':43.499356,'west':-97.239209}, - 'MS':{'name':'Mississippi','north':34.996052,'east':-88.097888,'south':30.173943,'west':-91.655009}, - 'MO':{'name':'Missouri','north':40.613640,'east':-89.098843,'south':35.995683,'west':-95.774704}, - 'MT':{'name':'Montana','north':49.001390,'east':-104.039138,'south':44.358221,'west':-116.050003}, - 'NE':{'name':'Nebraska','north':43.001708,'east':-95.308290,'south':39.999998,'west':-104.053514}, - 'NV':{'name':'Nevada','north':42.002207,'east':-114.039648,'south':35.001857,'west':-120.005746}, - 'NH':{'name':'New Hampshire','north':45.305476,'east':-70.610621,'south':42.696990,'west':-72.557247}, - 'NJ':{'name':'New Jersey','north':41.357423,'east':-73.893979,'south':38.928519,'west':-75.559614}, - 'NM':{'name':'New Mexico','north':37.000232,'east':-103.001964,'south':31.332301,'west':-109.050173}, - 'NY':{'name':'New York','north':45.015850,'east':-71.856214,'south':40.496103,'west':-79.762152}, - 'NC':{'name':'North Carolina','north':36.588117,'east':-75.460621,'south':33.842316,'west':-84.321869}, - 'ND':{'name':'North Dakota','north':49.000574,'east':-96.554507,'south':45.935054,'west':-104.048900}, - 'OH':{'name':'Ohio','north':41.977523,'east':-80.518693,'south':38.403202,'west':-84.820159}, - 'OK':{'name':'Oklahoma','north':37.002206,'east':-94.430662,'south':33.615833,'west':-103.002565}, - 'OR':{'name':'Oregon','north':46.292035,'east':-116.463504,'south':41.991794,'west':-124.566244}, - 'PA':{'name':'Pennsylvania','north':42.269860,'east':-74.689516,'south':39.719800,'west':-80.519891}, - 'PR':{'name':'Puerto Rico','north':18.515683,'east':-65.220703,'south':17.883280,'west':-67.945404}, - 'RI':{'name':'Rhode Island','north':42.018798,'east':-71.120570,'south':41.146339,'west':-71.862772}, - 'SC':{'name':'South Carolina','north':35.215402,'east':-78.542030,'south':32.034600,'west':-83.353910}, - 'SD':{'name':'South Dakota','north':45.945450,'east':-96.436589,'south':42.479635,'west':-104.057698}, - 'TN':{'name':'Tennessee','north':36.678118,'east':-81.646900,'south':34.982972,'west':-90.310298}, - 'TX':{'name':'Texas','north':36.500704,'east':-93.508292,'south':25.837377,'west':-106.645646}, - 'VI':{'name':'United States Virgin Islands','north':18.412655,'east':-64.564907,'south':17.673976,'west':-65.085452}, - 'UT':{'name':'Utah','north':42.001567,'east':-109.041058,'south':36.997968,'west':-114.052962}, - 'VT':{'name':'Vermont','north':45.016659,'east':-71.464555,'south':42.726853,'west':-73.437740}, - 'VA':{'name':'Virginia','north':39.466012,'east':-75.242266,'south':36.540738,'west':-83.675395}, - 'WA':{'name':'Washington','north':49.002494,'east':-116.915989,'south':45.543541,'west':-124.763068}, - 'WV':{'name':'West Virginia','north':40.638801,'east':-77.719519,'south':37.201483,'west':-82.644739}, - 'WI':{'name':'Wisconsin','north':47.080621,'east':-86.805415,'south':42.491983,'west':-92.888114}, - 'WY':{'name':'Wyoming','north':45.005904,'east':-104.052160,'south':40.994746,'west':-111.056888} -} - -COUNTRIES={ - 'AU':{'name':'Australia','north':-9.088228,'east':168.224954,'south':-55.322817,'west':72.246094}, - 'AT':{'name':'Austria','north':49.020530,'east':17.160776,'south':46.372276,'west':9.530749}, - 'BE':{'name':'Belgium','north':51.551667,'east':6.408097,'south':49.496982,'west':2.388914}, - 'CH':{'name':'Switzerland','north':47.808465,'east':10.492294,'south':45.817995,'west':5.955911}, - 'DE':{'name':'Germany','north':55.099161,'east':15.041932,'south':47.270111,'west':5.866315}, - 'DK':{'name':'Denmark','north':57.952430,'east':15.553064,'south':54.451667,'west':7.715325}, - 'ES':{'name':'Spain','north':43.993309,'east':4.591888,'south':27.433543,'west':-18.393684}, - 'FR':{'name':'France','north':51.268318,'east':9.867834,'south':41.263219,'west':-5.453429}, - 'GR':{'name':'Greece','north':41.748886,'east':29.729699,'south':34.700610,'west':19.247788}, - 'IT':{'name':'Italy','north':47.092146,'east':18.784475,'south':35.288962,'west':6.627266}, - 'LU':{'name':'Luxembourg','north':50.430377,'east':6.034425,'south':49.496982,'west':4.968441}, - 'PT':{'name':'Portugal','north':42.154311,'east':-6.189159,'south':29.828802,'west':-31.557530}, - 'CA':{'name':'Canada','north':83.336213,'east':-52.323198,'south':41.676556,'west':-141.002750}, - 'GB':{'name':'United-Kingdom','north':25.224165,'east':55.160692,'south':25.222319,'west':55.157952} -} - -def check_dependencies(): - rv = True - if shutil.which('curl') is None: - print("Missing dependency: %scurl%s use your system package manager to install it" %( - '\033[1;31m', #start bold red - '\033[0m' #reset - )) - rv = False - if shutil.which('composite') is None: - print("Missing dependency: %sImageMagick%s (%scomposite%s binary) use your system package manager to install it" %( - '\033[1;31m', #start bold red - '\033[0m', #reset - '\033[1;31m', #start bold red - '\033[0m' #reset - - )) - rv = False - return rv - -def clamp(value, low_bound, high_bound): - return min(max(value, low_bound), high_bound) - -def geo_to_tile(latitude, longitude, level): - latitude = clamp(latitude, MIN_LAT, MAX_LAT) - longitude = clamp(longitude, MIN_LON, MAX_LON) - - x = (longitude + 180.0) / 360.0 - sin_lat = math.sin(latitude * math.pi/180.0) - y = 0.5 - math.log((1+sin_lat)/(1-sin_lat)) / (4*math.pi) - - mapsize = 256 * 1 << level - #Pixel coordinates - world_x = clamp(x*mapsize + 0.5, 0, mapsize-1) - world_y = clamp(y*mapsize + 0.5, 0, mapsize-1) - - tile_x = world_x // 256 - tile_y = world_y // 256 - - return tile_x, tile_y - -def download_tile_area(dest_dir,level, top, left, bottom, right, recover=False): - current_host = [0] * len(PROVIDERS) - - total=((bottom-top)+1)*((right-left)+1) - done=int(0) - print("Doing level %d: 0%%\r" % (level),end='',flush=True) - for tilex in range(int(left),int(right)+1): - for(tiley) in range(int(top), int(bottom)+1): - outfile='%s/%d/%d/%d.png'%(dest_dir,level,tilex,tiley) - if recover and os.path.exists(outfile): - continue - for i in range(len(PROVIDERS)): - final_tiley = tiley - if 'mode' in PROVIDERS[i] and PROVIDERS[i]['mode'] == 'tms': - # openaip layers use TMS, 0,0 is bottom left - # instead of top left, so we need to reverse y - tms_maxy = (1 << level) - 1 - tmsy = tms_maxy - tiley - #print("TMS converstion y: %d -> %d" % (tiley,tmsy)) - final_tiley = tmsy - if 'hosts' in PROVIDERS[i] and len(PROVIDERS[i]['hosts']) > 0: - turl = PROVIDERS[i]['url'] % ( - PROVIDERS[i]['hosts'][current_host[i]], - level, tilex, final_tiley - ) - current_host[i] += 1 - if current_host[i] == len(PROVIDERS[i]['hosts']): - current_host[i] = 0 - else: - turl = PROVIDERS[i]['url'] % (level, tilex, final_tiley) -# print("url: %s" % turl) - output = "%d.png" %i - subprocess.run(["curl", turl, "-o",output], - stderr=subprocess.DEVNULL, - stdout=subprocess.DEVNULL - ) - for i in range(1,len(PROVIDERS) - 1): - layer = "%d.png" %i - if not os.path.exists(layer): - continue - subprocess.run(["composite", layer, "0.png", "0.png"]) - os.unlink(layer) - os.makedirs('%s/%d/%d/' % (dest_dir,level,tilex),exist_ok=True) - os.rename("0.png", outfile) - done += 1 - print("Doing level %d: %0.2f%%\r" % (level, done/total*100.0),end='',flush=True) - print() #prints a \n - - -parser = argparse.ArgumentParser() -subparsers = parser.add_subparsers(help='sub-command help', - dest='command', - required=True -) - -# Global arguments -parser.add_argument('-l','--min-level', type=int, - help='Start grabbing tiles at given level (default 6)', - default=6 -) -parser.add_argument('-L','--max-level', type=int, - help='Stop grabbing tiles at given level (default 12)', - default=12 -) -parser.add_argument('-d','--dest-dir', type=str, - help='Where to put the files (default current directory)', - default='.' -) -parser.add_argument('-r','--resume', action="iframe.php?url=https%3A%2F%2Fgithub.com%2Fstore_true", - help='Do not override existing tiles', -) - -# Area subcommand -area_parser = subparsers.add_parser('area', help='Fetch an area based on lat/lon and radius') -area_parser.add_argument("latitude", type=float, help="latitude of the area center") -area_parser.add_argument("longitude", type=float, help="longitude of the area center") -area_parser.add_argument('-r','--radius', type=int, - help='Set the radius in nautical miles (default 6)', - default=6 -) - -# State subcommand -state_parser = subparsers.add_parser('state', help='Fetch tiles for a given state (TX/FL/etc.)',) -state_parser.add_argument("state_code", type=str, help="Code of the state to fetch") - -# State subcommand -country_parser = subparsers.add_parser('country', help='Fetch tiles for a given country (FR/UK/DE/etc.)',) -country_parser.add_argument("country_code", type=str, help="Code of the country") - - -args = parser.parse_args() -#Check deps before doing anything -if not check_dependencies(): - exit(-1) - - -north=0 -east=0 -south=0 -west=0 -if args.command == 'state': - if args.state_code not in STATES: - print("%s: Unknown code state, bailing out" % args.state_code) - exit(-1) - print("Fetching levels %d-%d for %s - %s" % ( - args.min_level,args.max_level, - args.state_code, STATES[args.state_code]['name'] - )) - north = STATES[args.state_code]['north'] - east = STATES[args.state_code]['east'] - south = STATES[args.state_code]['south'] - west = STATES[args.state_code]['west'] -elif args.command == 'country': - if args.country_code not in COUNTRIES: - print("%s: Unknown code state, bailing out" % args.country_code) - exit(-1) - print("Fetching levels %d-%d for %s - %s" % ( - args.min_level,args.max_level, - args.country_code, COUNTRIES[args.country_code]['name'] - )) - north = COUNTRIES[args.country_code]['north'] - east = COUNTRIES[args.country_code]['east'] - south = COUNTRIES[args.country_code]['south'] - west = COUNTRIES[args.country_code]['west'] -elif args.command == 'area': - print('Fetching %d km around center lat:%f lon:%f min-level:%d max-level:%d' % ( - args.radius, args.latitude, - args.longitude,args.min_level, args.max_level - )) - loc = GeoLocation.from_degrees(args.latitude, args.longitude) - distance = args.radius*1.852 # N.M to kilometers - SW_loc, NE_loc = loc.bounding_locations(distance) - - north = NE_loc.deg_lat - east = NE_loc.deg_lon - south = SW_loc.deg_lat - west = SW_loc.deg_lon - - -print("Fetching area:\nup left - up right: (%f,%f) - (%f,%f)\ndown left - down right: (%f,%f) - (%f,%f)" % ( - north, west, - north, east, - - south, west, - south, east, - ) -) - - -for level in range(args.min_level, args.max_level+1): - right, top = geo_to_tile(north, east, level) - left, bottom = geo_to_tile(south, west, level) - - #print("area in tiles - level %d: top:%d left:%d bottom: %d right:%d" % (level, top, left, bottom, right)) - - download_tile_area(args.dest_dir,level, top, left, bottom, right, args.resume) diff --git a/sdl-colors.h b/sdl-colors.h deleted file mode 100644 index 031aba7..0000000 --- a/sdl-colors.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef SDL_COLORS_H -#define SDL_COLORS_H - -#define SDL_WHITE (SDL_Color){255, 255, 255, SDL_ALPHA_OPAQUE} -#define SDL_RED (SDL_Color){255, 0, 0, SDL_ALPHA_OPAQUE} -#define SDL_GREEN (SDL_Color){0, 255, 0, SDL_ALPHA_OPAQUE} -#define SDL_CYAN (SDL_Color){0, 255, 255, SDL_ALPHA_OPAQUE} -#define SDL_YELLOW (SDL_Color){255, 255, 0, SDL_ALPHA_OPAQUE} -#define SDL_BLACK (SDL_Color){0, 0, 0, SDL_ALPHA_OPAQUE} -#define SDL_LIGHTGREY (SDL_Color){192, 192, 192, SDL_ALPHA_OPAQUE} -#define SDL_GREY (SDL_Color){64, 64, 64, SDL_ALPHA_OPAQUE} -#define SDL_TRANSPARENT (SDL_Color){0, 0, 0, SDL_ALPHA_TRANSPARENT} - - - -#define SDL_UBLACK(surface) (SDL_MapRGB((surface)->format, 0, 0,0)) -#define SDL_URED(surface) (SDL_MapRGB((surface)->format, 255, 0,0)) -#define SDL_UGREEN(surface) (SDL_MapRGB((surface)->format, 0, 255,0)) -#define SDL_UWHITE(surface) (SDL_MapRGB((surface)->format, 255, 255,255)) -#define SDL_UYELLOW(surface) (SDL_MapRGB((surface)->format, 255, 255,0)) -#define SDL_UGREY(surface) (SDL_MapRGB((surface)->format, 205, 205,205)) -#define SDL_UFBLUE(surface) (SDL_MapRGB((surface)->format, 0x11, 0x56, 0xFF)) //Fancy blue - -#define SDL_UCKEY(surface) (SDL_MapRGB((surface)->format, 255, 0,255)) - - -#endif /* SDL_COLORS_H */ diff --git a/sdl-pcf b/sdl-pcf deleted file mode 160000 index 6ffc227..0000000 --- a/sdl-pcf +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6ffc2275b23859ba41182a8e47497e49f88db109 diff --git a/sensors-data-source.c b/sensors-data-source.c deleted file mode 100644 index 17fceba..0000000 --- a/sensors-data-source.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include -#include - -#include "sensors-data-source.h" -#include "sensors/gps-sensor.h" - -#ifndef BNO080_DEV -#define BNO080_DEV "/dev/i2c-1" -#endif - -#ifndef ENABLE_MOCK_GPS -#define ENABLE_MOCK_GPS 0 -#endif - -static bool sensors_data_source_frame(SensorsDataSource *self, uint32_t dt); -static SensorsDataSource *sensors_data_source_dispose(SensorsDataSource *self); -static DataSourceOps sensors_data_source_ops = { - .frame = (DataSourceFrameFunc)sensors_data_source_frame, - .dispose = (DataSourceDisposeFunc)sensors_data_source_dispose -}; - -SensorsDataSource *sensors_data_source_new(void) -{ - SensorsDataSource *self; - - self = calloc(1, sizeof(SensorsDataSource)); - if(self){ - if(!sensors_data_source_init(self)){ - free(self); - return NULL; - } - } - return self; -} - -SensorsDataSource *sensors_data_source_init(SensorsDataSource *self) -{ - if(!data_source_init(DATA_SOURCE(self), &sensors_data_source_ops)) - return NULL; - - if(!bno080_init(&self->imu, 0x4b, BNO080_DEV)){ - printf("Couldn't initialize BNO0808 device, bailing out\n"); - exit(EXIT_FAILURE); - } - bno080_enable_feature(&self->imu, ROTATION_VECTOR); - - - if(!gps_sensor_init(&self->gps, "localhost", DEFAULT_GPSD_PORT)){ - printf("Couldn't initialize GPS, bailing out\n"); - exit(EXIT_FAILURE); - } - -#if !ENABLE_MOCK_GPS - gps_sensor_start(&self->gps); -#else - data_source_set_location( - DATA_SOURCE(self), &(LocationData){ - .super.latitude = 45.215470, - .super.longitude = 5.844828, - .altitude = 718.267245 - } - ); - - data_source_set_attitude( - DATA_SOURCE(self), &(AttitudeData){ - .roll = 0, - .pitch = 0, - .heading = 43.698940 - } - ); -#endif - return self; -} - -static SensorsDataSource *sensors_data_source_dispose(SensorsDataSource *self) -{ - bno080_dispose(&self->imu); - return self; -} - -static bool sensors_data_source_frame(SensorsDataSource *self, uint32_t dt) -{ - double roll, pitch, yaw; - double heading; - double lat, lon, alt; - bool rv; - - if(dt != 0 && dt < (1000/25)) //One update per 1/25 second - return false; - - bno080_hpr(&self->imu, &heading, &pitch, &roll); - data_source_set_attitude( - DATA_SOURCE(self), &(AttitudeData){ - .roll = roll, - .pitch = pitch, - .heading = heading - } - ); - -#if !ENABLE_MOCK_GPS - gps_sensor_get_fix(&self->gps, &lat, &lon, &alt); - data_source_set_location( - DATA_SOURCE(self), &(LocationData){ - .super.latitude = lat, - .super.longitude = lon, - .altitude = alt*3.281 /*Comes in meters(gps), must be in feets*/ - } - ); -#else - data_source_set_location( - DATA_SOURCE(self), &(LocationData){ - .super.latitude = 45.215470, - .super.longitude = 5.844828, - .altitude = 718.267245 - } - ); -#endif - - DATA_SOURCE(self)->has_fix = true; - return true; -} diff --git a/sensors-data-source.h b/sensors-data-source.h deleted file mode 100644 index a3acd1e..0000000 --- a/sensors-data-source.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef SENSORS_DATA_SOURCE_H -#define SENSORS_DATA_SOURCE_H - -#include "data-source.h" -#include "sensors/bno080/bno080.h" -#include "sensors/gps-sensor.h" - -typedef struct{ - DataSource super; - - Bno080 imu; - GpsSensor gps; -}SensorsDataSource; - -SensorsDataSource *sensors_data_source_new(void); -SensorsDataSource *sensors_data_source_init(SensorsDataSource *self); - -#endif /* SENSORS_DATA_SOURCE_H */ diff --git a/sensors/bno080 b/sensors/bno080 deleted file mode 160000 index b588df7..0000000 --- a/sensors/bno080 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b588df793a87383dcc79263bc750a4652a77a4f3 diff --git a/sensors/gps-sensor.c b/sensors/gps-sensor.c deleted file mode 100644 index 410eb71..0000000 --- a/sensors/gps-sensor.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include -#include -#include - -#include "gps-sensor.h" -#define GPSD_API_SWITCH 9 - -static void gps_sensor_set_fix(GpsSensor *self); -static void gps_sensor_worker(GpsSensor *self); - -#if GPSD_API_MAJOR_VERSION >= GPSD_API_SWITCH -static inline bool timespec_equal(struct timespec *t1, struct timespec *t2) -{ - return t1->tv_sec == t2->tv_sec && t1->tv_nsec == t2->tv_nsec; -} -#else -static inline bool timespec_equal(double *t1, double *t2) -{ - return *t1 == *t2; -} -#endif - -GpsSensor *gps_sensor_new(const char *server, const char *port) -{ - GpsSensor *self; - - self = calloc(1, sizeof(GpsSensor)); - if(self){ - if(!gps_sensor_init(self, server, port)){ - free(gps_sensor_dispose(self)); - return NULL; - } - } - return self; -} - -GpsSensor *gps_sensor_init(GpsSensor *self, const char *server, const char *port) -{ - int rv; - - rv = gps_open(server, port, &self->gpsdata); - if(rv != 0){ - printf("Couldn't connect to gpsd error %d (%s)\n", - errno, - gps_errstr(errno) - ); - return NULL; - } - gps_stream(&self->gpsdata, WATCH_ENABLE, NULL); - - self->timeout = 5; /* seconds */ - self->latitude = NAN; - - pthread_mutex_init(&self->mtx, NULL); - - return self; -} - -GpsSensor *gps_sensor_dispose(GpsSensor *self) -{ - pthread_cancel(self->tid); - gps_close(&self->gpsdata); - return self; -} - -int gps_sensor_start(GpsSensor *self) -{ - return pthread_create(&self->tid, NULL, (void*)gps_sensor_worker, self); -} - -bool gps_sensor_get_fix(GpsSensor *self, double *latitude, double *longitude, double *altitude) -{ - pthread_mutex_lock(&self->mtx); - *latitude = self->latitude; - *longitude = self->longitude; - *altitude = self->altitude; -#if 0 - printf("lat: %f lon: %f alt: %f\n", - self->gpsdata.fix.latitude, - self->gpsdata.fix.longitude, - self->gpsdata.fix.altitude - ); -#endif - pthread_mutex_unlock(&self->mtx); - return true; -} - -static void gps_sensor_set_fix(GpsSensor *self) -{ -#if GPSD_API_MAJOR_VERSION >= GPSD_API_SWITCH - struct timespec old_time; -#else - double old_time; -#endif - static double old_lat, old_lon; - static bool first = true; - - if(timespec_equal(&(self->gpsdata.fix.time), &old_time) || self->gpsdata.fix.mode < MODE_2D) - return; - old_time = self->gpsdata.fix.time; - - if(self->gpsdata.fix.latitude == old_lat && self->gpsdata.fix.longitude == old_lon) - return; - old_lat = self->gpsdata.fix.latitude; - old_lon = self->gpsdata.fix.longitude; - - pthread_mutex_lock(&self->mtx); - self->latitude = self->gpsdata.fix.latitude; - self->longitude = self->gpsdata.fix.longitude; - self->altitude = self->gpsdata.fix.altitude; -#if 0 - printf("lat: %f lon: %f alt: %f\n", - self->gpsdata.fix.latitude, - self->gpsdata.fix.longitude, - self->gpsdata.fix.altitude - ); -#endif - pthread_mutex_unlock(&self->mtx); -} - -/*loosly modeled after gpsd's gps_mainloop*/ -static void gps_sensor_worker(GpsSensor *self) -{ - int rv; - - for(;;){ - if(gps_waiting(&self->gpsdata, self->timeout * 1000000)){ -#if GPSD_API_MAJOR_VERSION >= GPSD_API_SWITCH - rv = gps_read(&self->gpsdata, NULL, 0); -#else - rv = gps_read(&self->gpsdata); -#endif - if(rv > 0){ - /*actually process data*/ - gps_sensor_set_fix(self); - } - }else{ - printf("Connection to gpsd lost, reconnecting in %ld seconds\n", - self->timeout - ); - sleep(self->timeout); - } - } -} diff --git a/sensors/gps-sensor.h b/sensors/gps-sensor.h deleted file mode 100644 index e0824f1..0000000 --- a/sensors/gps-sensor.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef GPS_SENSOR_H -#define GPS_SENSOR_H -#include -#include - -#include - -typedef struct{ - struct gps_data_t gpsdata; - time_t timeout; - - pthread_t tid; - pthread_mutex_t mtx; - - double latitude; - double longitude; - double altitude; -}GpsSensor; - -GpsSensor *gps_sensor_new(const char *server, const char *port); -GpsSensor *gps_sensor_init(GpsSensor *self, const char *server, const char *port); -GpsSensor *gps_sensor_dispose(GpsSensor *self); - -int gps_sensor_start(GpsSensor *self); -bool gps_sensor_get_fix(GpsSensor *self, double *latitude, double *longitude, double *altitude); -#endif /* GPS_SENSOR_H */ diff --git a/sfv-gauge.c b/sfv-gauge.c deleted file mode 100644 index f930d93..0000000 --- a/sfv-gauge.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include "sfv-gauge.h" - -/* A base class for all gauges that have a single float value - * Factor out setting the value with regard to animations and - * getting the value while animations are running - * - * Derivatives are juste supposed to wrap up the setter function - * if some filtering/clamping is neeeded and let client code use - * the getter. - * - * No virtual functions are implemented, derivatives init/dispose - * with base_gauge_init/base_gauge_dispose as if they where direct - * descents of BaseGauge. - * */ - - -/** - * @brief Sets the value either direcly or triggering a standard - * duration animation. - * - * Intented to be called be derivatives if wrapping is needed or - * by client code if the derived class doesn't provide a specific - * setter. - * - * @param self a SfvGauge or derivative - * @param value the value to set - * @animated true to use an animation from the current value to @p value - * @returns true on success, false otherwise. - */ -bool sfv_gauge_set_value(SfvGauge *self, float value, bool animated) -{ - bool rv = true; - BaseAnimation *animation; - -// printf("%s %p value: %f\n",__FUNCTION__, self, self->value); - if(animated){ - if(BASE_GAUGE(self)->nanimations == 0){ - animation = base_animation_new(TYPE_FLOAT, 1, &self->value); - base_gauge_add_animation(BASE_GAUGE(self), animation); - }else{ - animation = BASE_GAUGE(self)->animations[0]; - } - base_animation_start(animation, self->value, value, DEFAULT_DURATION); - }else{ - if(value != self->value){ - self->value = value; - BASE_GAUGE(self)->dirty = true; - } - } - return rv; -} - -/** - * @brief Retreives the value that has been set to the gauge. - * - * If an animation is currently running, this function will return - * the value that has been set to the gauge and not the current frame's - * intermediate displayed value. - * - * @param self a SfvGauge - * @return the value - */ -float sfv_gauge_get_value(SfvGauge *self) -{ - BaseAnimation *animation; - - if(BASE_GAUGE(self)->nanimations > 0){ - animation = BASE_GAUGE(self)->animations[0]; - if(!animation->finished) - return animation->end; - } - return self->value; -} diff --git a/sfv-gauge.h b/sfv-gauge.h deleted file mode 100644 index 16d1666..0000000 --- a/sfv-gauge.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef SFV_GAUGE_H -#define SFV_GAUGE_H - -#include "base-gauge.h" - -typedef struct{ - BaseGauge super; - - float value; -}SfvGauge; - -#define SFV_GAUGE(self) ((SfvGauge *)(self)) - - -bool sfv_gauge_set_value(SfvGauge *self, float value, bool animated); -float sfv_gauge_get_value(SfvGauge *self); -#endif /* SFV_GAUGE_H */ diff --git a/side-panel.c b/side-panel.c deleted file mode 100644 index 1047ab8..0000000 --- a/side-panel.c +++ /dev/null @@ -1,483 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include - -#include "base-gauge.h" -#include "elevator-gauge.h" -#include "fishbone-gauge.h" -#include "side-panel.h" - -#include "misc.h" -#include "resource-manager.h" -#include "sdl-colors.h" - -#define GROUP_SPACE 8 - -static void side_panel_render(SidePanel *self, Uint32 dt, RenderContext *ctx); -static BaseGaugeOps side_panel_ops = { - .render = (RenderFunc)side_panel_render, - .update_state = (StateUpdateFunc)NULL, - .dispose = (DisposeFunc)NULL -}; - -SidePanel *side_panel_new(int width, int height) -{ - SidePanel *rv; - - rv = calloc(1, sizeof(SidePanel)); - if(rv){ - if(!side_panel_init(rv, width, height)){ - return base_gauge_free(BASE_GAUGE(rv)); - } - } - return rv; -} - -/** - * - * Params are there for future use. As for now, only supported dimensions - * are 92x480. - * - */ -SidePanel *side_panel_init(SidePanel *self, int width, int height) -{ - - width = 95; - height = 480-1; /*SDL_gpu has a strange coordinates handling*/ - - base_gauge_init( - BASE_GAUGE(self), - &side_panel_ops, - width, - height - ); -#if 0 - self->egt = elevator_gauge_new(true, - Left, - resource_manager_get_font(TERMINUS_12), SDL_WHITE, - 300, 2300, 300, - 15, 80, - 0, NULL - ); - self->egt_txt = text_gauge_new("EGT °F", false, 92 - 10, 12); - text_gauge_set_static_font(self->egt_txt, - resource_manager_get_static_font(TERMINUS_12, - &SDL_WHITE, - 2, PCF_ALPHA, PCF_DIGITS - ) - ); - self->locations[EGT] = (SDL_Rect){ - .x = 0, - .y = 0, - .w = BASE_GAUGE(self->egt)->w, - .h = BASE_GAUGE(self->egt)->h - }; - self->locations[EGT_TXT] = (SDL_Rect){ - .x = 0, - .y = self->locations[EGT].y + self->locations[EGT].h + 1, - .w = BASE_GAUGE(self->egt_txt)->w, - .h = BASE_GAUGE(self->egt_txt)->h, - }; -#else - self->locations[EGT] = self->locations[EGT_TXT] = (SDL_Rect){0,0,0,0}; -#endif - self->rpm = elevator_gauge_new(true, - Left, - resource_manager_get_font(TERMINUS_12), SDL_WHITE, - 0, 3000, 300, - 15, 110, - 3,(ColorZone[]){{ - .from = 0, - .to = 2600, - .color = SDL_GREEN, - .flags = FromIncluded | ToIncluded - },{ - .from = 2600, - .to = 2800, - .color = SDL_YELLOW, - .flags = FromExcluded | ToIncluded - },{ - .from = 2800, - .to = 3000, - .color = SDL_RED, - .flags = FromExcluded | ToIncluded - }} - ); - self->rpm_txt = text_gauge_new("RPM", false, 92 - 10, 12); - text_gauge_set_static_font(self->rpm_txt, - resource_manager_get_static_font(TERMINUS_12, - &SDL_WHITE, - 2, PCF_ALPHA, PCF_DIGITS - ) - ); - self->locations[RPM] = (SDL_Rect){ - .x = 0, - .y = SDLExt_RectLastY(&self->locations[EGT_TXT]) + 4, - .w = base_gauge_w(BASE_GAUGE(self->rpm)), - .h = base_gauge_h(BASE_GAUGE(self->rpm)) - }; - self->locations[RPM_TXT] = (SDL_Rect){ - .x = 0, - .y = SDLExt_RectLastY(&self->locations[RPM]) + 2, - .w = base_gauge_w(BASE_GAUGE(self->rpm_txt)), - .h = base_gauge_h(BASE_GAUGE(self->rpm_txt)) - }; - - - /*Fuel flow*/ - self->fuel_flow_txt = text_gauge_new("FUEL FLOW", false, 92 - 10, 12); - text_gauge_set_static_font(self->fuel_flow_txt, - resource_manager_get_static_font(TERMINUS_12, - &SDL_WHITE, - 2, PCF_ALPHA, PCF_DIGITS - ) - ); - self->fuel_flow_value = text_gauge_new("GPH", false, 92 - 10, 12); - text_gauge_set_static_font(self->fuel_flow_value, - resource_manager_get_static_font(TERMINUS_12, - &SDL_WHITE, - 3, PCF_ALPHA, PCF_DIGITS, "." - ) - ); - self->locations[FUEL_FLOW_TXT] = (SDL_Rect){ - .x = 0, - .y = SDLExt_RectLastY(&self->locations[RPM_TXT]) + GROUP_SPACE, - .w = base_gauge_w(BASE_GAUGE(self->fuel_flow_txt)), - .h = base_gauge_h(BASE_GAUGE(self->fuel_flow_txt)) - }; - self->locations[FUEL_FLOW_VALUE] = (SDL_Rect){ - .x = 0, - .y = SDLExt_RectLastY(&self->locations[FUEL_FLOW_TXT]) + 2, - .w = base_gauge_w(BASE_GAUGE(self->fuel_flow_value)), - .h = base_gauge_h(BASE_GAUGE(self->fuel_flow_value)) - }; - - - /*Oil temperature*/ - self->oil_temp_txt = text_gauge_new("OIL TEMP", false, 92 - 10, 12); - text_gauge_set_static_font(self->oil_temp_txt, - resource_manager_get_static_font(TERMINUS_12, - &SDL_WHITE, - 2, PCF_ALPHA, PCF_DIGITS - ) - ); - self->oil_temp = fishbone_gauge_new(true, - resource_manager_get_font(TERMINUS_12), SDL_WHITE, - 0, 300, -1, - 92 - 10, 15, - 3,(ColorZone[]){{ - .from = 0, - .to = 200, - .color = SDL_GREEN, - .flags = FromIncluded | ToIncluded - },{ - .from = 200, - .to = 250, - .color = SDL_YELLOW, - .flags = FromExcluded | ToIncluded - },{ - .from = 250, - .to = 300, - .color = SDL_RED, - .flags = FromExcluded | ToIncluded - }} - ); - self->locations[OIL_TEMP_TXT] = (SDL_Rect){ - .x = 0, - .y = SDLExt_RectLastY(&self->locations[FUEL_FLOW_VALUE]) + GROUP_SPACE, - .w = base_gauge_w(BASE_GAUGE(self->oil_temp_txt)), - .h = base_gauge_h(BASE_GAUGE(self->oil_temp_txt)) - }; - self->locations[OIL_TEMP] = (SDL_Rect){ - .x = 0, - .y = SDLExt_RectLastY(&self->locations[OIL_TEMP_TXT]) +2, - .w = base_gauge_w(BASE_GAUGE(self->oil_temp)), - .h = base_gauge_h(BASE_GAUGE(self->oil_temp)) - }; - - - /*Oil pressure*/ - self->oil_press_txt = text_gauge_new("OIL PRESS", false, 92 - 10, 12); - text_gauge_set_static_font(self->oil_press_txt, - resource_manager_get_static_font(TERMINUS_12, - &SDL_WHITE, - 2, PCF_ALPHA, PCF_DIGITS - ) - ); - self->oil_press = fishbone_gauge_new(true, - resource_manager_get_font(TERMINUS_12), SDL_WHITE, - 0, 100, 20, - 92 - 10, 15, - 4,(ColorZone[]){{ - .from = 0, - .to = 20, - .color = SDL_RED, - .flags = FromIncluded | ToIncluded - },{ - .from = 20, - .to = 60, - .color = SDL_GREEN, - .flags = FromExcluded | ToIncluded - },{ - .from = 60, - .to = 80, - .color = SDL_YELLOW, - .flags = FromExcluded | ToIncluded - },{ - .from = 80, - .to = 100, - .color = SDL_RED, - .flags = FromExcluded | ToIncluded - }} - ); - self->locations[OIL_PRESS_TXT] = (SDL_Rect){ - .x = 0, - .y = SDLExt_RectLastY(&self->locations[OIL_TEMP]) + GROUP_SPACE, - .w = base_gauge_w(BASE_GAUGE(self->oil_press_txt)), - .h = base_gauge_h(BASE_GAUGE(self->oil_press_txt)) - }; - self->locations[OIL_PRESS] = (SDL_Rect){ - .x = 0, - .y = SDLExt_RectLastY(&self->locations[OIL_PRESS_TXT]) +2, - .w = base_gauge_w(BASE_GAUGE(self->oil_press)), - .h = base_gauge_h(BASE_GAUGE(self->oil_press)) - }; - - - /*CHT*/ - self->cht_txt = text_gauge_new("CHT", false, 92 - 10, 12); - text_gauge_set_static_font(self->cht_txt, - resource_manager_get_static_font(TERMINUS_12, - &SDL_WHITE, - 2, PCF_ALPHA, PCF_DIGITS - ) - ); - self->cht = fishbone_gauge_new(true, - resource_manager_get_font(TERMINUS_12), SDL_WHITE, - 0, 600, -1, - 92 - 10, 15, - 3,(ColorZone[]){{ - .from = 0, - .to = 400, - .color = SDL_GREEN, - .flags = FromIncluded | ToIncluded - },{ - .from = 400, - .to = 550, - .color = SDL_YELLOW, - .flags = FromExcluded | ToIncluded - },{ - .from = 550, - .to = 600, - .color = SDL_RED, - .flags = FromExcluded | ToIncluded - }} - ); - self->locations[CHT_TXT] = (SDL_Rect){ - .x = 0, - .y = SDLExt_RectLastY(&self->locations[OIL_PRESS]) + GROUP_SPACE, - .w = base_gauge_w(BASE_GAUGE(self->cht_txt)), - .h = base_gauge_h(BASE_GAUGE(self->cht_txt)) - }; - self->locations[CHT] = (SDL_Rect){ - .x = 0, - .y = SDLExt_RectLastY(&self->locations[CHT_TXT]) +2, - .w = base_gauge_w(BASE_GAUGE(self->cht)), - .h = base_gauge_h(BASE_GAUGE(self->cht)) - }; - - - /*Fuel pressure*/ - self->fuel_px_txt = text_gauge_new("FUEL PRESSURE", false, 92 - 10, 12); - text_gauge_set_static_font(self->fuel_px_txt, - resource_manager_get_static_font(TERMINUS_12, - &SDL_WHITE, - 2, PCF_ALPHA, PCF_DIGITS - ) - ); - self->fuel_px = fishbone_gauge_new(true, - resource_manager_get_font(TERMINUS_12), SDL_WHITE, - 0, 9, -1, - 92 - 10, 15, - 3,(ColorZone[]){{ - .from = 0, - .to = 2, - .color = SDL_RED, - .flags = FromIncluded | ToIncluded - },{ - .from = 2, - .to = 6, - .color = SDL_GREEN, - .flags = FromExcluded | ToIncluded - },{ - .from = 6, - .to = 9, - .color = SDL_RED, - .flags = FromExcluded | ToIncluded - }} - ); - self->locations[FUEL_PX_TXT] = (SDL_Rect){ - .x = 0, - .y = SDLExt_RectLastY(&self->locations[CHT]) + GROUP_SPACE, - .w = base_gauge_w(BASE_GAUGE(self->fuel_px_txt)), - .h = base_gauge_h(BASE_GAUGE(self->fuel_px_txt)) - }; - self->locations[FUEL_PX] = (SDL_Rect){ - .x = 0, - .y = SDLExt_RectLastY(&self->locations[FUEL_PX_TXT]) +2, - .w = base_gauge_w(BASE_GAUGE(self->fuel_px)), - .h = base_gauge_h(BASE_GAUGE(self->fuel_px)) - }; - - - /*Fuel QTY*/ - self->fuel_qty_txt = text_gauge_new("FUEL QTY GAL", false, 92 - 10, 12); - text_gauge_set_static_font(self->fuel_qty_txt, - resource_manager_get_static_font(TERMINUS_12, - &SDL_WHITE, - 2, PCF_ALPHA, PCF_DIGITS - ) - ); - self->fuel_qty = fishbone_gauge_new(true, - resource_manager_get_font(TERMINUS_12), SDL_WHITE, - 0, 25, 5, - 92 - 10, 15, - 3,(ColorZone[]){{ - .from = 0, - .to = 2, - .color = SDL_RED, - .flags = FromIncluded | ToIncluded - },{ - .from = 2, - .to = 10, - .color = SDL_YELLOW, - .flags = FromExcluded | ToIncluded - },{ - .from = 10, - .to = 25, - .color = SDL_GREEN, - .flags = FromExcluded | ToIncluded - }} - ); - self->locations[FUEL_QTY_TXT] = (SDL_Rect){ - .x = 0, - .y = SDLExt_RectLastY(&self->locations[FUEL_PX]) + GROUP_SPACE, - .w = base_gauge_w(BASE_GAUGE(self->fuel_qty_txt)), - .h = base_gauge_h(BASE_GAUGE(self->fuel_qty_txt)) - }; - self->locations[FUEL_QTY] = (SDL_Rect){ - .x = 0, - .y = SDLExt_RectLastY(&self->locations[FUEL_QTY_TXT]) +2, - .w = base_gauge_w(BASE_GAUGE(self->fuel_qty)), - .h = base_gauge_h(BASE_GAUGE(self->fuel_qty)) - - }; - -#if 1 - SDL_Rect reference = {0,0,base_gauge_w(BASE_GAUGE(self)),base_gauge_h(BASE_GAUGE(self))}; - for(int i = 0; i < NSidePanelLocations; i++){ - int tmpy = self->locations[i].y; - SDLExt_RectAlign(&self->locations[i], &reference, HALIGN_CENTER); - self->locations[i].y = tmpy; - - } -#endif - base_gauge_add_child(BASE_GAUGE(self), BASE_GAUGE(self->rpm_txt), - self->locations[RPM_TXT].x, - self->locations[RPM_TXT].y - ); - base_gauge_add_child(BASE_GAUGE(self), BASE_GAUGE(self->rpm), - self->locations[RPM].x, - self->locations[RPM].y - ); - base_gauge_add_child(BASE_GAUGE(self), BASE_GAUGE(self->fuel_flow_txt), - self->locations[FUEL_FLOW_TXT].x, - self->locations[FUEL_FLOW_TXT].y - ); - base_gauge_add_child(BASE_GAUGE(self), BASE_GAUGE(self->fuel_flow_value), - self->locations[FUEL_FLOW_VALUE].x, - self->locations[FUEL_FLOW_VALUE].y - ); - base_gauge_add_child(BASE_GAUGE(self), BASE_GAUGE(self->oil_temp_txt), - self->locations[OIL_TEMP_TXT].x, - self->locations[OIL_TEMP_TXT].y - ); - base_gauge_add_child(BASE_GAUGE(self), BASE_GAUGE(self->oil_temp), - self->locations[OIL_TEMP].x, - self->locations[OIL_TEMP].y - ); - base_gauge_add_child(BASE_GAUGE(self), BASE_GAUGE(self->oil_press_txt), - self->locations[OIL_PRESS_TXT].x, - self->locations[OIL_PRESS_TXT].y - ); - base_gauge_add_child(BASE_GAUGE(self), BASE_GAUGE(self->oil_press), - self->locations[OIL_PRESS].x, - self->locations[OIL_PRESS].y - ); - base_gauge_add_child(BASE_GAUGE(self), BASE_GAUGE(self->cht_txt), - self->locations[CHT_TXT].x, - self->locations[CHT_TXT].y - ); - base_gauge_add_child(BASE_GAUGE(self), BASE_GAUGE(self->cht), - self->locations[CHT].x, - self->locations[CHT].y - ); - base_gauge_add_child(BASE_GAUGE(self), BASE_GAUGE(self->fuel_px_txt), - self->locations[FUEL_PX_TXT].x, - self->locations[FUEL_PX_TXT].y - ); - base_gauge_add_child(BASE_GAUGE(self), BASE_GAUGE(self->fuel_px), - self->locations[FUEL_PX].x, - self->locations[FUEL_PX].y - ); - base_gauge_add_child(BASE_GAUGE(self), BASE_GAUGE(self->fuel_qty_txt), - self->locations[FUEL_QTY_TXT].x, - self->locations[FUEL_QTY_TXT].y - ); - base_gauge_add_child(BASE_GAUGE(self), BASE_GAUGE(self->fuel_qty), - self->locations[FUEL_QTY].x, - self->locations[FUEL_QTY].y - ); - return self; -} - -void side_panel_set_rpm(SidePanel *self, float value) -{ - elevator_gauge_set_value(self->rpm, value, true); - text_gauge_set_value_formatn(self->rpm_txt, - 10, - "%04d RPM", (int)value - ); -} - -void side_panel_set_fuel_flow(SidePanel *self, float value) -{ - text_gauge_set_value_formatn(self->fuel_flow_value, - 10, - "%0.2f GPH", value - ); -} - - -void side_panel_engine_data_changed(SidePanel *self, EngineData *newv) -{ - side_panel_set_rpm(self, newv->rpm); - side_panel_set_fuel_flow(self, newv->fuel_flow); - side_panel_set_oil_temp(self, newv->oil_temp); - side_panel_set_oil_press(self, newv->oil_press); - side_panel_set_cht(self, newv->cht); - side_panel_set_fuel_px(self, newv->fuel_px); - side_panel_set_fuel_qty(self, newv->fuel_qty); -} - -static void side_panel_render(SidePanel *self, Uint32 dt, RenderContext *ctx) -{ - base_gauge_fill(BASE_GAUGE(self),ctx, NULL, &SDL_BLACK, false); - base_gauge_draw_outline(BASE_GAUGE(self), ctx, &SDL_WHITE, NULL); -} diff --git a/side-panel.h b/side-panel.h deleted file mode 100644 index c220b64..0000000 --- a/side-panel.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef SIDE_PANEL_H -#define SIDE_PANEL_H - -#include "base-gauge.h" -#include "elevator-gauge.h" -#include "fishbone-gauge.h" -#include "text-gauge.h" -#include "data-source.h" - -typedef enum{ - EGT, - EGT_TXT, - - RPM, - RPM_TXT, - - FUEL_FLOW_TXT, - FUEL_FLOW_VALUE, - - OIL_TEMP_TXT, - OIL_TEMP, - - OIL_PRESS_TXT, - OIL_PRESS, - - CHT_TXT, - CHT, - - FUEL_PX_TXT, - FUEL_PX, - - FUEL_QTY_TXT, - FUEL_QTY, - - NSidePanelLocations -}SidePanelLocations; - -typedef struct{ - BaseGauge super; - - ElevatorGauge *egt; - TextGauge *egt_txt; - - ElevatorGauge *rpm; - TextGauge *rpm_txt; - - TextGauge *fuel_flow_txt; - TextGauge *fuel_flow_value; - - TextGauge *oil_temp_txt; - FishboneGauge *oil_temp; - - TextGauge *oil_press_txt; - FishboneGauge *oil_press; - - TextGauge *cht_txt; - FishboneGauge *cht; - - TextGauge *fuel_px_txt; - FishboneGauge *fuel_px; - - TextGauge *fuel_qty_txt; - FishboneGauge *fuel_qty; - - SDL_Rect locations[NSidePanelLocations]; -}SidePanel; - -SidePanel *side_panel_new(int width, int height); -SidePanel *side_panel_init(SidePanel *self, int width, int height); - -void side_panel_set_rpm(SidePanel *self, float value); -void side_panel_set_fuel_flow(SidePanel *self, float value); - -static inline void side_panel_set_oil_temp(SidePanel *self, float value) -{ - fishbone_gauge_set_value(self->oil_temp, value, true); -} - -static inline void side_panel_set_oil_press(SidePanel *self, float value) -{ - fishbone_gauge_set_value(self->oil_press, value, true); -} - -static inline void side_panel_set_cht(SidePanel *self, float value) -{ - fishbone_gauge_set_value(self->cht, value, true); -} - -static inline void side_panel_set_fuel_px(SidePanel *self, float value) -{ - fishbone_gauge_set_value(self->fuel_px, value, true); -} - -static inline void side_panel_set_fuel_qty(SidePanel *self, float value) -{ - fishbone_gauge_set_value(self->fuel_qty, value, true); -} - - -void side_panel_engine_data_changed(SidePanel *self, EngineData *newv); -#endif /* SIDE_PANEL_H */ - diff --git a/sofis-bno080-rpi.png b/sofis-bno080-rpi.png new file mode 100644 index 0000000..4bf04eb Binary files /dev/null and b/sofis-bno080-rpi.png differ diff --git a/sofis-demo-240p.gif b/sofis-demo-240p.gif new file mode 100644 index 0000000..356b6b9 Binary files /dev/null and b/sofis-demo-240p.gif differ diff --git a/sofis-demo-480p.gif b/sofis-demo-480p.gif new file mode 100644 index 0000000..ccb8c09 Binary files /dev/null and b/sofis-demo-480p.gif differ diff --git a/sofis-direct-to.gif b/sofis-direct-to.gif new file mode 100644 index 0000000..206934e Binary files /dev/null and b/sofis-direct-to.gif differ diff --git a/sofis-rpi-b.png b/sofis-rpi-b.png new file mode 100644 index 0000000..438f409 Binary files /dev/null and b/sofis-rpi-b.png differ diff --git a/static-map-provider.c b/static-map-provider.c deleted file mode 100644 index f5db75d..0000000 --- a/static-map-provider.c +++ /dev/null @@ -1,324 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include -#include - -#include "static-map-provider.h" -#include "http-download.h" - -static bool static_map_provider_read_config(StaticMapProvider *self); -static const char *static_map_provider_url_template_set(StaticMapProviderUrlTemplate *self, - uint8_t level, - int32_t x, int32_t y); - -static GenericLayer *static_map_provider_get_tile(StaticMapProvider *self, uintf8_t level, int32_t x, int32_t y); -static StaticMapProvider *static_map_provider_dispose(StaticMapProvider *self); -static MapProviderOps static_map_provider_ops = { - .get_tile = (MapProviderGetTileFunc)static_map_provider_get_tile, - .dispose = (MapProviderDisposeFunc)static_map_provider_dispose -}; - -StaticMapProvider *static_map_provider_new(const char *home, const char *format, - intf8_t priority) -{ - StaticMapProvider *self; - - self = calloc(1, sizeof(StaticMapProvider)); - if(self){ - if(!static_map_provider_init(self, home, format, priority)) - return (StaticMapProvider*)map_provider_free(MAP_PROVIDER(self)); - } - return self; -} - -StaticMapProvider *static_map_provider_init(StaticMapProvider *self, const char *home, - const char *format, intf8_t priority) -{ - map_provider_init( - MAP_PROVIDER(self), - &static_map_provider_ops, - priority - ); - - self->home = strdup(home); - if(!self->home) return NULL; - - self->format = strdup(format); - if(!self->format) return NULL; - - /* format is HOME/LL/XXXXXXX/YYYYYYY.FORMAT - * We go up to level 23 which means tileX/Y - * can reach 8388607 which is 7 digits long - */ - self->bsize = strlen(self->home) - + 1 /*slash*/ - + 2 /*LL*/ - + 1 /*slash*/ - + 7 /*XXXXXXX*/ - + 1 /*slash*/ - + 7 /*YYYYYYY*/ - + 1 /*dot*/ - + strlen(self->format) - + 1; /*null byte*/ - self->buffer = malloc(sizeof(char)*self->bsize); - if(!self->buffer) return NULL; - - /*The read config can fail and the provider still be - * usable: no config file, etc.*/ - static_map_provider_read_config(self); - - return self; -} - -static StaticMapProvider *static_map_provider_dispose(StaticMapProvider *self) -{ - if(self->home) - free(self->home); - if(self->format) - free(self->format); - if(self->url.base) - free(self->url.base); - if(self->buffer) - free(self->buffer); - return self; -} - -/** - * @brief Loads up a GenericLayer from a set of coordinates. - * - * Client code is responsible for freeing the layer @see generic_layer_free - * - * @param self a StaticMapProvider - * @param level Zoom level - * @param x x-coordinate of the tile in the map - * @param y y-coordinate of the tile in the map - * @return A GenericLayer pointer or NULL on failure - */ -static GenericLayer *static_map_provider_get_tile(StaticMapProvider *self, uintf8_t level, int32_t x, int32_t y) -{ - - if(MAP_PROVIDER(self)->nareas && !map_provider_has_tile(MAP_PROVIDER(self), level, x, y)) - return NULL; - - snprintf(self->buffer, self->bsize, "%s/%d/%d/%d.%s", self->home, level, x, y, self->format); - if(access(self->buffer, F_OK) != 0){ - /* This is downloading feature is not intended to make it - * into the final version. Maps should be deployed/installed - * as a whole (maybe using a grabbing script) and not tile by tile - * and certainly not at runtime. - * - * This feature is nonetheless very useful for the dev version - * and for demos. - * */ - if(!self->url.base) return NULL; - static_map_provider_url_template_set(&self->url, level, x, y); - if(!http_download_file(self->url.base, self->buffer)){ - return NULL; - } - } - - return generic_layer_new_from_file(self->buffer); -} - - -/** - * @brief Creates a fetching URL for a given tile. - * - * The caller should not free the returned value. Any subsequent call - * will alter the pointed value. Use a copy if you want the value to survive - * the next call. Be cautious when using threads. Only one thread should call - * it and distribute copies to others. - * - * @param self The MapProviderUrlTemplate - * @param level the level - * @parm x The x coordinates of the tile within level @param level - * @parm y The y coordinates of the tile within level @param level - * @return The url that can be used to fetch the tile. - */ -static const char *static_map_provider_url_template_set(StaticMapProviderUrlTemplate *self, - uint8_t level, - int32_t x, int32_t y) -{ - char tmp; - - if(self->is_tms){ - uint32_t tms_maxy = (1 << level) - 1; - y = tms_maxy - y; - } - - /* snprintf behavior regarding size and the null byte is - * implementation-defined. On Linux it will always null-terminate - * the string, therefore we print the full size and we save/restore - * the char just after the place holder*/ - tmp = self->lvl[7]; /*byte index 7 is the 8th*/ - /* %LEVEL% is 7 bytes so we need to print seven digits to override it fully - * size is 8 to output a null byte *after* the level. If it was 7 and strncpy - * impl wants to null-terminate the string (as in Linux) it would break the number - * instead of stopping after the last digit and omitting the null byte - * */ - snprintf(self->lvl, 8, "%07d", level); - self->lvl[7] = tmp; - - tmp = self->tilex[8];/*byte index 8 is the 9th*/ - /*%TILE_X% is 8 bytes long*/ - snprintf(self->tilex, 9, "%08d", x); - self->tilex[8] = tmp; - - tmp = self->tiley[8]; - /*%TILE_X% is 8 bytes long*/ - snprintf(self->tiley, 9, "%08d", y); - self->tiley[8] = tmp; - - return self->base; -} - -/** - * @brief parse an 'area' config line and fill @param values. - * - * @param line: A line, without trailing spaces that begins with 'area:' - * (without quotes). - * @param area: A MapProviderArea to fill with parsed values. - * - * @return true on success, false otherwise - */ -static bool map_config_read_area(const char *line, MapProviderArea *area) -{ - size_t found; - char *parts[5]; - const char *area_parts[] = {"level","left","right","top","bottom"}; - - found = split_str(line+5, isspace, parts, 5); - if(found < 5){ - printf("Missing area part: %s\n", area_parts[found]); - return false; - } - - /* TODO: replace atoi() with something that can handle - * failures.*/ - area->level = atoi(parts[0]); - area->left = atoi(parts[1]); - area->right = atoi(parts[2]); - area->top = atoi(parts[3]); - area->bottom = atoi(parts[4]); - return true; -} - -/** - * @brief parse a 'src' config line and turn it into a MapProviderUrlTemplate. - * - * @param line: A line, without trailing spaces that begins with 'src:' - * (without quotes). - * @param url: Address to a MapProviderUrlTemplate to be inited. - * - * @return true on success, false otherwise - */ -static bool map_config_read_url_template(uintf8_t keyword_len, const char *line, StaticMapProviderUrlTemplate *url) -{ - char *tmp; - char *base; - int len; - - tmp = nibble_spaces(line+keyword_len, 0); - if(!tmp) return false; - url->base = strdup(tmp); - len = strlen(url->base); - if(url->base[len-1] == '\n') - url->base[len-1] = '\0'; - printf("Found url: %s\n", url->base); - - url->lvl = strstr(url->base, "%LEVEL%"); - if(!url->lvl){ - printf("Missing %%LEVE%% placeholder in url template\n"); - goto out; - } - - url->tilex = strstr(url->base, "%TILE_X%"); - if(!url->tilex){ - printf("Missing %%TILE_X%% placeholder in url template\n"); - goto out; - } - - url->tiley = strstr(url->base, "%TILE_Y%"); - if(!url->tiley){ - printf("Missing %%TILE_Y%% placeholder in url template\n"); - goto out; - } - return true; - -out: - free(url->base); - url->base = NULL; - return false; -} - -static bool static_map_provider_read_config(StaticMapProvider *self) -{ - char *filename; - size_t flen; - FILE *fp; - - char *line = NULL; - size_t aline; - size_t read; - - /* returns the number of characters that would have been printed - * *excluding* the null byte */ - flen = snprintf(NULL, 0, "%s/map.conf", self->home); - /*TODO: add malloca/freea to revert to the heap when size is too big (1KB?)*/ - filename = alloca((flen+1)*sizeof(char)); - /*size must include the null byte if we don't want the string to be truncated*/ - snprintf(filename, flen+1, "%s/map.conf", self->home); - - fp = fopen(filename,"r"); - if(!fp) - return false; - - size_t found; - - char *iter; - /*First, count the number of areas/levels bounds described in the file*/ - off_t mark = ftell(fp); - size_t nareas = 0; - while((read = getline(&line, &aline, fp)) != -1){ - iter = nibble_spaces(line, read); - if(!iter || *iter == '#' ) continue; - - if(!strncmp(iter, "area:",5)) nareas++; - } - /*Then allocate and fill*/ - printf("Found %zu level areas\n", nareas); - map_provider_set_nareas(MAP_PROVIDER(self), nareas); - - fseek(fp, mark, SEEK_SET); - size_t current_area = 0; - while((read = getline(&line, &aline, fp)) != -1){ - iter = nibble_spaces(line, read); - if(!iter || *iter == '#' ) continue; - - if(MAP_PROVIDER(self)->areas && !strncmp(iter, "area:",5)){ - bool rv; - rv = map_config_read_area(iter, &MAP_PROVIDER(self)->areas[current_area++]); - if(!rv) continue; /*TODO: (currently) does nothing*/ - }else if(!strncmp(iter, "src:",4)){ - bool rv; - rv = map_config_read_url_template(4, iter, &self->url); - if(!rv) continue; /*TODO: (currently) does nothing*/ - }else if(!strncmp(iter, "src-tms:",8)){ - bool rv; - rv = map_config_read_url_template(8, iter, &self->url); - if(!rv) continue; - self->url.is_tms = true; - } - - } - free(line); - fclose(fp); - - return true; -} diff --git a/static-map-provider.h b/static-map-provider.h deleted file mode 100644 index c4a572c..0000000 --- a/static-map-provider.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef STATIC_MAP_PROVIDER_H -#define STATIC_MAP_PROVIDER_H -#include "map-provider.h" - -typedef struct{ - /* In TMS mode, the Y axis (tiles coordinates within the world map) - * is reversed*/ - bool is_tms; - char *base; - - char *lvl; - char *tilex; - char *tiley; -}StaticMapProviderUrlTemplate; - - -typedef struct{ - MapProvider super; - - char *home; - char *format; /*tile file extension*/ - char *buffer; /*store filenames*/ - size_t bsize; /*in bytes*/ - StaticMapProviderUrlTemplate url; -}StaticMapProvider; - -StaticMapProvider *static_map_provider_new(const char *home, const char *format, intf8_t priority); - -StaticMapProvider *static_map_provider_init(StaticMapProvider *self, const char *home, - const char *format, intf8_t priority); - -#endif /* STATIC_MAP_PROVIDER_H */ diff --git a/stratux-data-source.c b/stratux-data-source.c deleted file mode 100644 index 054f9a3..0000000 --- a/stratux-data-source.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include "stratux-data-source.h" -#include "http-request.h" - -#include "misc.h" -#include - -//#define API_ENDPOINT "http://127.0.0.1/getSituation" -#define API_ENDPOINT "http://192.168.10.1/getSituation" - -char *json_get_value(const char *json, const char *key, size_t *keylen); -double json_get_double_value(const char *json, const char *key, const char *nan_value); - - -static bool stratux_data_source_frame(StratuxDataSource *self, uint32_t dt); -static StratuxDataSource *stratux_data_source_dispose(StratuxDataSource *self); -static DataSourceOps stratux_data_source_ops = { - .frame = (DataSourceFrameFunc)stratux_data_source_frame, - .dispose = (DataSourceDisposeFunc)stratux_data_source_dispose -}; - - -StratuxDataSource *stratux_data_source_new() -{ - StratuxDataSource *self; - - self = calloc(1, sizeof(StratuxDataSource)); - if(self){ - if(!stratux_data_source_init(self)){ - free(self); - return NULL; - } - } - return self; -} - -StratuxDataSource *stratux_data_source_init(StratuxDataSource *self) -{ - if(!data_source_init(DATA_SOURCE(self), &stratux_data_source_ops)) - return NULL; - self->buf = http_buffer_new(0); - if(!self->buf) - return NULL; - - return self; -} - -static StratuxDataSource *stratux_data_source_dispose(StratuxDataSource *self) -{ - if(self->buf){ - if(self->buf->buffer) - free(self->buf->buffer); - free(self->buf); - } - return self; -} - - -static bool stratux_data_source_frame(StratuxDataSource *self, uint32_t dt) -{ - bool rv; - double lat, lon, alt; - double roll, pitch,heading, mheading; - double vertical_speed_gps; - double vertical_speed_baro; - - rv = http_request(API_ENDPOINT, &self->buf); - if(!rv) return false; - - lat = json_get_double_value(self->buf->buffer, "GPSLatitude", NULL); - lon = json_get_double_value(self->buf->buffer, "GPSLongitude", NULL); - alt = json_get_double_value(self->buf->buffer, "GPSHeightAboveEllipsoid", NULL); - - roll = json_get_double_value(self->buf->buffer, "AHRSRoll", "3276.7"); - pitch = json_get_double_value(self->buf->buffer, "AHRSPitch", "3276.7"); - heading = json_get_double_value(self->buf->buffer, "AHRSGyroHeading", "3276.7"); - mheading = json_get_double_value(self->buf->buffer, "AHRSMagHeading", "3276.7"); - - vertical_speed_gps = json_get_double_value(self->buf->buffer, "GPSVerticalSpeed", NULL); - vertical_speed_baro = json_get_double_value(self->buf->buffer, "BaroVerticalSpeed", NULL); - - if(!isnan(heading)) - heading = fmod(heading, 360.0); - if(!isnan(mheading)) - mheading = fmod(mheading, 360.0); - data_source_set_location( - DATA_SOURCE(self), &(LocationData){ - .super.latitude = lat, - .super.longitude = lon, - .altitude = alt - } - ); - - data_source_set_dynamics( - DATA_SOURCE(self), &(DynamicsData){ - .airspeed = DATA_SOURCE(self)->dynamics.airspeed, - .vertical_speed = vertical_speed_gps, - .slip_rad = DATA_SOURCE(self)->dynamics.slip_rad - } - ); - - - float new_heading; - if(!isnan(heading)) - new_heading = fmod(heading,360.0); - else if(!isnan(mheading)) - new_heading = fmod(mheading,360.0); - - data_source_set_attitude( - DATA_SOURCE(self), &(AttitudeData){ - .roll = roll, - .pitch = pitch, - .heading = new_heading - } - ); - -#if 0 - printf("lat: %f lon: %f, alt: %f\n" - "roll: %f pitch: %f heading(gyro): %f heading(mag): %f\n", - lat, lon, alt, - roll, pitch, heading, mheading - ); -#endif - self->buf->len = 0; - - DATA_SOURCE(self)->has_fix = true; - return true; -} - -/** - * This is very primitive and won't work with complex (i.e. - * nested arrays/objects) types - * - */ -char *json_get_value(const char *json, const char *key, size_t *keylen) -{ - char *rv; - char *kend; - - rv = strstr(json, key); - if(!rv) return NULL; - - rv = strchr(rv, ':'); - if(!rv) return NULL; - - rv = nibble_spaces(rv+1, 0); - if(!rv) return NULL; - - kend = strchr(rv, ','); - if(!kend) - kend = strchr(rv, '}'); - if(kend && keylen) - *keylen = kend - rv; - - return rv; -} - -double json_get_double_value(const char *json, const char *key, const char *nan_value) -{ - double rv; - char *strval; - size_t len; - - strval = json_get_value(json, key, &len); - if(!strval) return NAN; - - if(nan_value && !strncmp(strval, nan_value, len)) return NAN; - - return strtod(strval, NULL); -} - diff --git a/stratux-data-source.h b/stratux-data-source.h deleted file mode 100644 index e7f09ac..0000000 --- a/stratux-data-source.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef STRATUX_DATA_SOURCE_H -#define STRATUX_DATA_SOURCE_H -#include "data-source.h" -#include "http-buffer.h" - -typedef struct{ - DataSource super; - - HttpBuffer *buf; -}StratuxDataSource; - - -StratuxDataSource *stratux_data_source_new(); -StratuxDataSource *stratux_data_source_init(StratuxDataSource *self); -#endif /* STRATUX_DATA_SOURCE_H */ diff --git a/switches.defaults b/switches.defaults deleted file mode 100644 index 152e8fa..0000000 --- a/switches.defaults +++ /dev/null @@ -1,9 +0,0 @@ -BUILD_MODE=debug -ENABLE_3D=1 -USE_GLES=0 -TINY_TEXTURES=0 -NO_PRELOAD=0 -HAVE_IGN_OACI_MAP=0 -GL_LIB=GL -BNO080_DEV=\"/dev/i2c-1\" -ENABLE_MOCK_GPS=0 diff --git a/tape-gauge.c b/tape-gauge.c deleted file mode 100644 index 282a2c1..0000000 --- a/tape-gauge.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include - -#include "base-gauge.h" -#include "sfv-gauge.h" -#include "tape-gauge.h" -#include "ladder-gauge.h" -#include "odo-gauge.h" -#include "misc.h" - -static void tape_gauge_update_state(TapeGauge *self, Uint32 dt); -static BaseGaugeOps tape_gauge_ops = { - .render = (RenderFunc)NULL, - .update_state = (StateUpdateFunc)tape_gauge_update_state, - .dispose = (DisposeFunc)NULL -}; - -TapeGauge *tape_gauge_new(int w, int h, LadderPageDescriptor *descriptor, - Alignment align, int xoffset, - int nbarrels, ...) -{ - TapeGauge *self, *rv; - va_list args; - - self = calloc(1, sizeof(TapeGauge)); - if(self){ - va_start(args, nbarrels); - rv = tape_gauge_vainit(self, w, h, descriptor, align, xoffset, nbarrels, args); - va_end(args); - if(!rv) - return base_gauge_free(BASE_GAUGE(self)); - } - return self; - -} - -TapeGauge *tape_gauge_vainit(TapeGauge *self, int w, int h, - LadderPageDescriptor *descriptor, - Alignment align, int xoffset, - int nbarrels, va_list ap) -{ - int aligned_x; - int common_y; - int max_x; - - self->ladder = ladder_gauge_new(w, h, (LadderPageDescriptor *)descriptor, -1); - if(!self->ladder) - return NULL; - base_gauge_add_child(BASE_GAUGE(self), BASE_GAUGE(self->ladder), 0, 0); - - self->odo = odo_gauge_vanew_multiple(-1, nbarrels, ap); - if(!self->odo) - return NULL;/*self->ladder is a child, base_gauge_free will free it*/ - - base_gauge_init(BASE_GAUGE(self), - &tape_gauge_ops, - base_gauge_w(BASE_GAUGE(self->ladder)), - base_gauge_h(BASE_GAUGE(self->ladder)) - ); - - common_y = SDLExt_RectMidY(&BASE_GAUGE(self->ladder)->frame) - - SDLExt_RectMidY(&BASE_GAUGE(self->odo)->frame); - /*-1 to prevent from eating the border*/ - max_x = SDLExt_RectLastX(&BASE_GAUGE(self->ladder)->frame) - 1 - - base_gauge_w(BASE_GAUGE(self->odo)); - if(align == AlignRight) - aligned_x = max_x; - else /*Left*/ - aligned_x = 0 + 1; /*+1 border, don't eat*/ - base_gauge_add_child(BASE_GAUGE(self), BASE_GAUGE(self->odo), - clamp(aligned_x + xoffset, 1, max_x), /*1 and not 0, preserve border*/ - common_y - ); - - return self; -} - -bool tape_gauge_set_value(TapeGauge *self, float value, bool animated) -{ - BaseAnimation *animation; - - if(animated){ - if(BASE_GAUGE(self)->nanimations == 0){ - animation = base_animation_new(TYPE_FLOAT, 2, - &SFV_GAUGE(self->ladder)->value, - &SFV_GAUGE(self->odo)->value - ); - base_gauge_add_animation(BASE_GAUGE(self), animation); - }else{ - animation = BASE_GAUGE(self)->animations[0]; - } - base_animation_start(animation, SFV_GAUGE(self->ladder)->value, value, DEFAULT_DURATION); - }else{ - ladder_gauge_set_value(self->ladder, value, false); - odo_gauge_set_value(self->odo, value, false); - BASE_GAUGE(self)->dirty = true; - } - - return true; -} - -float tape_gauge_get_value(TapeGauge *self) -{ - return sfv_gauge_get_value(SFV_GAUGE(self->ladder)); -} - -static void tape_gauge_update_state(TapeGauge *self, Uint32 dt) -{ - BaseAnimation *animation; - - if(BASE_GAUGE(self)->nanimations > 0){ - animation = BASE_GAUGE(self)->animations[0]; - if(!animation->finished){ - BASE_GAUGE(self->ladder)->dirty = true; - BASE_GAUGE(self->odo)->dirty = true; - } - } -} diff --git a/tape-gauge.h b/tape-gauge.h deleted file mode 100644 index 0f21b6f..0000000 --- a/tape-gauge.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef TAPE_GAUGE_H -#define TAPE_GAUGE_H - -#include "base-gauge.h" -#include "ladder-gauge.h" -#include "odo-gauge.h" - -typedef enum{ - AlignLeft, - AlignRight -}Alignment; - -typedef struct{ - BaseGauge super; - - LadderGauge *ladder; - OdoGauge *odo; -}TapeGauge; - -TapeGauge *tape_gauge_new(int w, int h, LadderPageDescriptor *descriptor, - Alignment align, int xoffset, - int nbarrels, ...); -TapeGauge *tape_gauge_vainit(TapeGauge *self, int w, int h, - LadderPageDescriptor *descriptor, - Alignment align, int xoffset, - int nbarrels, va_list ap); - -bool tape_gauge_set_value(TapeGauge *self, float value, bool animated); -float tape_gauge_get_value(TapeGauge *self); -#endif /* TAPE_GAUGE_H */ diff --git a/testbench/airspeed.c b/testbench/airspeed.c deleted file mode 100644 index 997093b..0000000 --- a/testbench/airspeed.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include - -#include -#include - -#include "base-gauge.h" -#include "base-widget.h" -#include "softkey.h" -#include "data-source.h" - -#include "mock-data-source.h" -#include "resource-manager.h" -#include "airspeed-indicator.h" - - -#include "sdl-colors.h" - -#define SCREEN_WIDTH 640 -#define SCREEN_HEIGHT 480 - -//#define SCREEN_WIDTH 800 -//#define SCREEN_HEIGHT 480 - - -AirspeedIndicator *asi = NULL; - -float ias = 10.0; - -#define IAS_INC 1 - - - -//typedef void (*EventListenerFunc)(void *self, BaseWidget *sender); -void button_soft_key_listener(EventListener *self, Softkey *sender) -{ - if(sender->state == SOFTKEY_STATE_RELEASED) - softkey_set_state(sender, SOFTKEY_STATE_PRESSED); - else - softkey_set_state(sender, SOFTKEY_STATE_RELEASED); -} - -/*Return true to quit the app*/ -bool handle_keyboard(SDL_KeyboardEvent *event, Uint32 elapsed) -{ - - if(event->state != SDL_PRESSED) return false; - switch(event->keysym.sym){ - case SDLK_ESCAPE: - return true; - break; - case SDLK_UP: - ias += IAS_INC; - airspeed_indicator_set_value(asi, ias); - break; - case SDLK_DOWN: - ias -= IAS_INC; - airspeed_indicator_set_value(asi, ias); - break; - case SDLK_SPACE: - printf("IAS is: %f\n", ias); - break; - default: - break; - } - - return false; -} - -/*Return true to quit the app*/ -bool handle_events(Uint32 elapsed) -{ - SDL_Event event; - - while(SDL_PollEvent(&event) == 1){ - switch(event.type){ - case SDL_QUIT: - return true; - break; - case SDL_WINDOWEVENT: - if(event.window.event == SDL_WINDOWEVENT_CLOSE) - return true; - break; - case SDL_KEYUP: - case SDL_KEYDOWN: - return handle_keyboard(&(event.key), elapsed); - break; - } - } - return false; -} - - -int main(int argc, char **argv) -{ - bool done; - int i; - float oldv[5] = {0,0,0,0,0}; - RenderTarget rtarget; - -#if USE_SDL_GPU - GPU_Target* gpu_screen = NULL; - - GPU_SetRequiredFeatures(GPU_FEATURE_BASIC_SHADERS); - gpu_screen = GPU_InitRenderer(GPU_RENDERER_OPENGL_2, SCREEN_WIDTH, SCREEN_HEIGHT, GPU_DEFAULT_INIT_FLAGS); - if(gpu_screen == NULL){ - GPU_LogError("Initialization Error: Could not create a renderer with proper feature support for this demo.\n"); - return 1; - } - rtarget.target = gpu_screen; -#else - SDL_Window* window = NULL; - SDL_Surface* screenSurface = NULL; - - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - return 1; - } -// SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); -// SDL_SetHintWithPriority(SDL_HINT_RENDER_SCALE_QUALITY, "0", SDL_HINT_OVERRIDE); - - window = SDL_CreateWindow( - "hello_sdl2", - SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - SCREEN_WIDTH, SCREEN_HEIGHT, - SDL_WINDOW_SHOWN - ); - if (window == NULL) { - fprintf(stderr, "could not create window: %s\n", SDL_GetError()); - return 1; - } - - screenSurface = SDL_GetWindowSurface(window); - if(!screenSurface){ - printf("Error: %s\n",SDL_GetError()); - exit(-1); - } - rtarget.surface = screenSurface; -#endif - data_source_set((DataSource*)mock_data_source_new()); - - - asi = airspeed_indicator_new(50,60,85,155,200); - airspeed_indicator_set_value(asi, ias); - - - SDL_Rect vrect = {96,68,0,0}; - -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - - - done = false; - Uint32 ticks; - Uint32 last_ticks = 0; - Uint32 elapsed = 0; - Uint32 acc = 0; - i = 3; - do{ - ticks = SDL_GetTicks(); - elapsed = ticks - last_ticks; - acc += elapsed; - - done = handle_events(elapsed); - - /* Not having this in the loop breaks ladder-gauge display - * TODO: Check why and fix - * */ -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - base_gauge_render(BASE_GAUGE(asi), elapsed, &(RenderContext){rtarget, &vrect, NULL}); -#if USE_SDL_GPU - GPU_Flip(gpu_screen); -#else - SDL_UpdateWindowSurface(window); -#endif -#if 1 - if(elapsed < 200){ - SDL_Delay(200 - elapsed); - } -#endif - if(acc >= 10000){ - acc = 0; - } - - last_ticks = ticks; - }while(!done); - - base_gauge_free(BASE_GAUGE(asi)); - resource_manager_shutdown(); - data_source_free(data_source_get_instance()); -#if USE_SDL_GPU - GPU_Quit(); -#else - SDL_DestroyWindow(window); - SDL_Quit(); -#endif - return 0; - -} - diff --git a/testbench/alt-group.c b/testbench/alt-group.c deleted file mode 100644 index befdd13..0000000 --- a/testbench/alt-group.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include - -#include -#include - -#include "base-gauge.h" -#include "data-source.h" - -#include "mock-data-source.h" -#include "resource-manager.h" -#include "alt-group.h" - -#define SCREEN_WIDTH 640 -#define SCREEN_HEIGHT 480 - - -AltGroup *group = NULL; - -float alt = 900.0; -//float vs = 2000.0; -float vs = 0.0; - -#define VARIO_INC 100 -#define ALT_INC 150 - - -/*Return true to quit the app*/ -bool handle_keyboard(SDL_KeyboardEvent *event, Uint32 elapsed) -{ - - if(event->state != SDL_PRESSED) return false; - switch(event->keysym.sym){ - case SDLK_ESCAPE: - return true; - break; - case SDLK_UP: - alt += ALT_INC; - alt_group_set_altitude(group, alt); - alt_group_set_values(group, alt, vs); - break; - case SDLK_DOWN: - alt -= ALT_INC; - alt_group_set_altitude(group, alt); - alt_group_set_values(group, alt, vs); - break; - case SDLK_p: - vs += VARIO_INC; - alt_group_set_vertical_speed(group, vs); - break; - case SDLK_m: - vs -= VARIO_INC; - alt_group_set_vertical_speed(group, vs); - break; - case SDLK_SPACE: - printf("Alt is: %f\n", alt); - printf("Vs is: %f\n", vs); - break; - default: - break; - } - - return false; -} - -/*Return true to quit the app*/ -bool handle_events(Uint32 elapsed) -{ - SDL_Event event; - - while(SDL_PollEvent(&event) == 1){ - switch(event.type){ - case SDL_QUIT: - return true; - break; - case SDL_WINDOWEVENT: - if(event.window.event == SDL_WINDOWEVENT_CLOSE) - return true; - break; - case SDL_KEYUP: - case SDL_KEYDOWN: - return handle_keyboard(&(event.key), elapsed); - break; - } - } - return false; -} - - - - -int main(int argc, char **argv) -{ - bool done; - int i; - float oldv[5] = {0,0,0,0,0}; - RenderTarget rtarget; - -#if USE_SDL_GPU - GPU_Target* gpu_screen = NULL; - - GPU_SetRequiredFeatures(GPU_FEATURE_BASIC_SHADERS); - gpu_screen = GPU_InitRenderer(GPU_RENDERER_OPENGL_2, SCREEN_WIDTH, SCREEN_HEIGHT, GPU_DEFAULT_INIT_FLAGS); - if(gpu_screen == NULL){ - GPU_LogError("Initialization Error: Could not create a renderer with proper feature support for this demo.\n"); - return 1; - } - rtarget.target = gpu_screen; -#else - SDL_Window* window = NULL; - SDL_Surface* screenSurface = NULL; - - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - return 1; - } -// SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); -// SDL_SetHintWithPriority(SDL_HINT_RENDER_SCALE_QUALITY, "0", SDL_HINT_OVERRIDE); - - window = SDL_CreateWindow( - "hello_sdl2", - SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - SCREEN_WIDTH, SCREEN_HEIGHT, - SDL_WINDOW_SHOWN - ); - if (window == NULL) { - fprintf(stderr, "could not create window: %s\n", SDL_GetError()); - return 1; - } - - screenSurface = SDL_GetWindowSurface(window); - if(!screenSurface){ - printf("Error: %s\n",SDL_GetError()); - exit(-1); - } - rtarget.surface = screenSurface; -#endif - data_source_set((DataSource*)mock_data_source_new()); - - group = alt_group_new(); - alt_group_set_values(group, alt, vs); - - - - // SDL_Rect airect = {SCREEN_WIDTH/2 + 90,SCREEN_HEIGHT/2-20,0,0}; - SDL_Rect airect = {439,51,0,0}; - -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - - - done = false; - Uint32 ticks; - Uint32 last_ticks = 0; - Uint32 elapsed = 0; - Uint32 acc = 0; - i = 3; - do{ - ticks = SDL_GetTicks(); - elapsed = ticks - last_ticks; - acc += elapsed; - - done = handle_events(elapsed); - - /* Not having this in the loop breaks ladder-gauge display - * TODO: Check why and fix - * */ -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - base_gauge_render(BASE_GAUGE(group), elapsed, &(RenderContext){rtarget, &airect, NULL}); -#if USE_SDL_GPU - GPU_Flip(gpu_screen); -#else - SDL_UpdateWindowSurface(window); -#endif -#if 1 - if(elapsed < 200){ - SDL_Delay(200 - elapsed); - } -#endif - if(acc >= 10000){ - acc = 0; - } - - last_ticks = ticks; - }while(!done); - - base_gauge_free(BASE_GAUGE(group)); - resource_manager_shutdown(); - data_source_free(data_source_get_instance()); -#if USE_SDL_GPU - GPU_Quit(); -#else - SDL_DestroyWindow(window); - SDL_Quit(); -#endif - return 0; - -} - diff --git a/testbench/alt-indicator.c b/testbench/alt-indicator.c deleted file mode 100644 index c83195e..0000000 --- a/testbench/alt-indicator.c +++ /dev/null @@ -1,252 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include -#include -#include - -#include -#include - -#include "base-gauge.h" -#include "base-widget.h" -#include "basic-hud.h" -#include "button.h" -#include "softkey.h" -#include "compass-gauge.h" -#include "data-source.h" -#include "elevator-gauge.h" -#include "fishbone-gauge.h" -#include "ladder-gauge.h" -#include "alt-ladder-page-descriptor.h" - -#include "ladder-page.h" -#include "mock-data-source.h" -#include "odo-gauge.h" -#include "alt-indicator.h" -#include "pfd-toplevel-softkey-model.h" -#include "resource-manager.h" -#include "SDL_pcf.h" -#include "side-panel.h" -#include "text-gauge.h" -#include "vertical-stair.h" -#include "alt-group.h" -#include "airspeed-indicator.h" -#include "attitude-indicator.h" -#include "roll-slip-gauge.h" -#include "tape-gauge.h" -#include "map-gauge.h" -#include "route-map-provider.h" -#include "direct-to-dialog.h" -#include "softkey-bar.h" - - -#include "sdl-colors.h" -#include "res-dirs.h" - -#define SCREEN_WIDTH 640 -#define SCREEN_HEIGHT 480 - - -AltIndicator *alt_ind = NULL; - -float gval = 0.0; -float alt = 900.0; -float odo_val = 0.0; -//float vs = 2000.0; -float vs = 0.0; -float ias = 10.0; -//float pitch = 2.19; -float pitch = 0.0; -float roll = 0.0; -float slip_deg = 0.0; -float fishval = 0.0; -float eleval = 0.0; -char txtbuf[256]; -float heading = 0.0; - -#define ODO_INC 1 -#define VARIO_INC 100 -#define IAS_INC 1 -#define ALT_INC 150 -#define PITCH_INC 1; -#define ROLL_INC 1; -#define SLIP_INC 5.0; -#define GVAL_INC 10.0; -#define HEADING_INC 5.0; -#define FISHVAL_INC 1.0; -#define ELEVAL_INC 100.0; - - - -/*Return true to quit the app*/ -bool handle_keyboard(SDL_KeyboardEvent *event, Uint32 elapsed) -{ - - if(event->state != SDL_PRESSED) return false; - switch(event->keysym.sym){ - case SDLK_ESCAPE: - return true; - break; - case SDLK_UP: - /*vs = compute_vs(alt, alt+ALT_INC, elapsed);*/ - alt += ALT_INC; - alt_indicator_set_value(alt_ind, alt, true); - break; - case SDLK_DOWN: - /*vs = compute_vs(alt, alt-ALT_INC, elapsed);*/ - alt -= ALT_INC; - alt_indicator_set_value(alt_ind, alt, true); - break; - case SDLK_SPACE: - printf("Alt is: %f\n", alt); - break; - default: - break; - } - - return false; -} - -/*Return true to quit the app*/ -bool handle_events(Uint32 elapsed) -{ - SDL_Event event; - - while(SDL_PollEvent(&event) == 1){ - switch(event.type){ - case SDL_QUIT: - return true; - break; - case SDL_WINDOWEVENT: - if(event.window.event == SDL_WINDOWEVENT_CLOSE) - return true; - break; - case SDL_KEYUP: - case SDL_KEYDOWN: - return handle_keyboard(&(event.key), elapsed); - break; - } - } - return false; -} - - - -int main(int argc, char **argv) -{ - bool done; - int i; - float oldv[5] = {0,0,0,0,0}; - RenderTarget rtarget; - -#if USE_SDL_GPU - GPU_Target* gpu_screen = NULL; - - GPU_SetRequiredFeatures(GPU_FEATURE_BASIC_SHADERS); - gpu_screen = GPU_InitRenderer(GPU_RENDERER_OPENGL_2, SCREEN_WIDTH, SCREEN_HEIGHT, GPU_DEFAULT_INIT_FLAGS); - if(gpu_screen == NULL){ - GPU_LogError("Initialization Error: Could not create a renderer with proper feature support for this demo.\n"); - return 1; - } - rtarget.target = gpu_screen; -#else - SDL_Window* window = NULL; - SDL_Surface* screenSurface = NULL; - - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - return 1; - } -// SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); -// SDL_SetHintWithPriority(SDL_HINT_RENDER_SCALE_QUALITY, "0", SDL_HINT_OVERRIDE); - - window = SDL_CreateWindow( - "hello_sdl2", - SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - SCREEN_WIDTH, SCREEN_HEIGHT, - SDL_WINDOW_SHOWN - ); - if (window == NULL) { - fprintf(stderr, "could not create window: %s\n", SDL_GetError()); - return 1; - } - - screenSurface = SDL_GetWindowSurface(window); - if(!screenSurface){ - printf("Error: %s\n",SDL_GetError()); - exit(-1); - } - rtarget.surface = screenSurface; -#endif - data_source_set((DataSource*)mock_data_source_new()); - - alt_ind = alt_indicator_new(); - alt_indicator_set_value(alt_ind, alt, true); - - // SDL_Rect airect = {SCREEN_WIDTH/2 + 90,SCREEN_HEIGHT/2-20,0,0}; - SDL_Rect airect = {439,51,0,0}; - -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - - done = false; - Uint32 ticks; - Uint32 last_ticks = 0; - Uint32 elapsed = 0; - Uint32 acc = 0; - i = 3; - do{ - ticks = SDL_GetTicks(); - elapsed = ticks - last_ticks; - acc += elapsed; - - done = handle_events(elapsed); - - /* Not having this in the loop breaks ladder-gauge display - * TODO: Check why and fix - * */ -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - base_gauge_render(BASE_GAUGE(alt_ind), elapsed, &(RenderContext){rtarget, &airect, NULL}); -#if USE_SDL_GPU - GPU_Flip(gpu_screen); -#else - SDL_UpdateWindowSurface(window); -#endif -#if 1 - if(elapsed < 200){ - SDL_Delay(200 - elapsed); - } -#endif - if(acc >= 10000){ - acc = 0; - } - - last_ticks = ticks; - }while(!done); - - base_gauge_free(BASE_GAUGE(alt_ind)); - resource_manager_shutdown(); - data_source_free(data_source_get_instance()); -#if USE_SDL_GPU - GPU_Quit(); -#else - SDL_DestroyWindow(window); - SDL_Quit(); -#endif - return 0; - -} - diff --git a/testbench/attitude.c b/testbench/attitude.c deleted file mode 100644 index 50ef8da..0000000 --- a/testbench/attitude.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include - -#include -#include - -#include "base-gauge.h" -#include "data-source.h" - -#include "mock-data-source.h" -#include "resource-manager.h" -#include "attitude-indicator.h" - -#define SCREEN_WIDTH 640 -#define SCREEN_HEIGHT 480 - -//#define SCREEN_WIDTH 800 -//#define SCREEN_HEIGHT 480 - - -AttitudeIndicator *ai = NULL; - -//float pitch = 2.19; -float pitch = 0.0; -float roll = 0.0; - -#define PITCH_INC 1; -#define ROLL_INC 1; - - - -/*Return true to quit the app*/ -bool handle_keyboard(SDL_KeyboardEvent *event, Uint32 elapsed) -{ - - if(event->state != SDL_PRESSED) return false; - switch(event->keysym.sym){ - case SDLK_ESCAPE: - return true; - break; - case SDLK_x: - pitch -= PITCH_INC; - attitude_indicator_set_pitch(ai, pitch, true); - break; - case SDLK_s: - pitch += PITCH_INC; - attitude_indicator_set_pitch(ai, pitch, true); - break; - case SDLK_c: - roll -= ROLL_INC; - attitude_indicator_set_roll(ai, roll, true); - case SDLK_d: - roll += ROLL_INC; - attitude_indicator_set_roll(ai, roll, true); - break; - case SDLK_SPACE: - printf("Roll is: %f\n", roll); - printf("pitch is: %f\n", pitch); - break; - default:{ - } - } - - return false; -} - -/*Return true to quit the app*/ -bool handle_events(Uint32 elapsed) -{ - SDL_Event event; - - while(SDL_PollEvent(&event) == 1){ - switch(event.type){ - case SDL_QUIT: - return true; - break; - case SDL_WINDOWEVENT: - if(event.window.event == SDL_WINDOWEVENT_CLOSE) - return true; - break; - case SDL_KEYUP: - case SDL_KEYDOWN: - return handle_keyboard(&(event.key), elapsed); - break; - } - } - return false; -} - - - -int main(int argc, char **argv) -{ - bool done; - int i; - float oldv[5] = {0,0,0,0,0}; - RenderTarget rtarget; - -#if USE_SDL_GPU - GPU_Target* gpu_screen = NULL; - - GPU_SetRequiredFeatures(GPU_FEATURE_BASIC_SHADERS); - gpu_screen = GPU_InitRenderer(GPU_RENDERER_OPENGL_2, SCREEN_WIDTH, SCREEN_HEIGHT, GPU_DEFAULT_INIT_FLAGS); - if(gpu_screen == NULL){ - GPU_LogError("Initialization Error: Could not create a renderer with proper feature support for this demo.\n"); - return 1; - } - rtarget.target = gpu_screen; -#else - SDL_Window* window = NULL; - SDL_Surface* screenSurface = NULL; - - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - return 1; - } -// SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); -// SDL_SetHintWithPriority(SDL_HINT_RENDER_SCALE_QUALITY, "0", SDL_HINT_OVERRIDE); - - window = SDL_CreateWindow( - "hello_sdl2", - SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - SCREEN_WIDTH, SCREEN_HEIGHT, - SDL_WINDOW_SHOWN - ); - if (window == NULL) { - fprintf(stderr, "could not create window: %s\n", SDL_GetError()); - return 1; - } - - screenSurface = SDL_GetWindowSurface(window); - if(!screenSurface){ - printf("Error: %s\n",SDL_GetError()); - exit(-1); - } - rtarget.surface = screenSurface; -#endif - data_source_set((DataSource*)mock_data_source_new()); - - - ai = attitude_indicator_new(640,480); - attitude_indicator_set_pitch(ai, pitch, true); - attitude_indicator_set_roll(ai, roll, true); - - - SDL_Rect whole = {0,0,SCREEN_WIDTH,SCREEN_HEIGHT}; - -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - done = false; - Uint32 ticks; - Uint32 last_ticks = 0; - Uint32 elapsed = 0; - Uint32 acc = 0; - i = 3; - do{ - ticks = SDL_GetTicks(); - elapsed = ticks - last_ticks; - acc += elapsed; - - done = handle_events(elapsed); - - /* Not having this in the loop breaks ladder-gauge display - * TODO: Check why and fix - * */ -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - base_gauge_render(BASE_GAUGE(ai), elapsed, &(RenderContext){rtarget, &whole, NULL}); - -#if USE_SDL_GPU - GPU_Flip(gpu_screen); -#else - SDL_UpdateWindowSurface(window); -#endif -#if 1 - if(elapsed < 200){ - SDL_Delay(200 - elapsed); - } -#endif - if(acc >= 10000){ - /*if(ANIMATED_GAUGE(ai)->value != oldv[3]){*/ - /*printf("Attitude pitch: %0.2f\n",ANIMATED_GAUGE(ai)->value);*/ - /*oldv[3] = ANIMATED_GAUGE(ai)->value;*/ - /*}*/ -#if 0 - if(ai->rollslip->super.value != oldv[4]){ - printf("Attitude roll: %0.2f\n", ai->rollslip->super.value); - oldv[4] = ai->rollslip->super.value; - } -#endif - - acc = 0; - } - - last_ticks = ticks; - }while(!done); - - base_gauge_free(BASE_GAUGE(ai)); - resource_manager_shutdown(); - data_source_free(data_source_get_instance()); -#if USE_SDL_GPU - GPU_Quit(); -#else - SDL_DestroyWindow(window); - SDL_Quit(); -#endif - return 0; - -} - diff --git a/testbench/basic-hud.c b/testbench/basic-hud.c deleted file mode 100644 index 8c1b1ff..0000000 --- a/testbench/basic-hud.c +++ /dev/null @@ -1,252 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include - -#include -#include - -#include "base-gauge.h" -#include "basic-hud.h" -#include "data-source.h" - -#include "mock-data-source.h" -#include "resource-manager.h" - - -#define SCREEN_WIDTH 640 -#define SCREEN_HEIGHT 480 - - - -BasicHud *hud = NULL; - -float alt = 900.0; -float vs = 0.0; -float ias = 10.0; -//float pitch = 2.19; -float pitch = 0.0; -float roll = 0.0; -float heading = 0.0; - -#define VARIO_INC 100 -#define IAS_INC 1 -#define ALT_INC 150 -#define PITCH_INC 1; -#define ROLL_INC 1; -#define HEADING_INC 5.0; - - -/*Return true to quit the app*/ -bool handle_keyboard(SDL_KeyboardEvent *event, Uint32 elapsed) -{ - - if(event->state != SDL_PRESSED) return false; - switch(event->keysym.sym){ - case SDLK_ESCAPE: - return true; - break; - case SDLK_a: - ias += IAS_INC; - basic_hud_set(hud, 1, AIRSPEED, ias); - break; - case SDLK_z: - ias -= IAS_INC; - basic_hud_set(hud, 1, AIRSPEED, ias); - break; - case SDLK_UP: - alt += ALT_INC; - basic_hud_set(hud, 1, ALTITUDE, alt); - break; - case SDLK_DOWN: - alt -= ALT_INC; - basic_hud_set(hud, 1, ALTITUDE, alt); - break; - case SDLK_p: - vs += VARIO_INC; - basic_hud_set(hud, 1, VERTICAL_SPEED, vs); - break; - case SDLK_m: - vs -= VARIO_INC; - basic_hud_set(hud, 1, VERTICAL_SPEED, vs); - break; - case SDLK_x: - pitch -= PITCH_INC; - basic_hud_set(hud, 1, PITCH, pitch); - break; - case SDLK_s: - pitch += PITCH_INC; - basic_hud_set(hud, 1, PITCH, pitch); - break; - case SDLK_c: - roll -= ROLL_INC; - basic_hud_set(hud, 1, ROLL, roll); - break; - case SDLK_d: - roll += ROLL_INC; - basic_hud_set(hud, 1, ROLL, roll); - break; - case SDLK_e: - heading += HEADING_INC; - heading = fmod(heading, 360.0); - if(heading < 0) - heading += 360.0; - basic_hud_set(hud, 1, HEADING, heading); - break; - case SDLK_SPACE: - printf("Alt is: %f\n", alt); - printf("Roll is: %f\n", roll); - printf("pitch is: %f\n", pitch); - printf("heading is: %f\n", heading); - break; - default: - break; - } - - return false; -} - -/*Return true to quit the app*/ -bool handle_events(Uint32 elapsed) -{ - SDL_Event event; - - while(SDL_PollEvent(&event) == 1){ - switch(event.type){ - case SDL_QUIT: - return true; - break; - case SDL_WINDOWEVENT: - if(event.window.event == SDL_WINDOWEVENT_CLOSE) - return true; - break; - case SDL_KEYUP: - case SDL_KEYDOWN: - return handle_keyboard(&(event.key), elapsed); - break; - } - } - return false; -} - - - - -int main(int argc, char **argv) -{ - bool done; - int i; - float oldv[5] = {0,0,0,0,0}; - RenderTarget rtarget; - -#if USE_SDL_GPU - GPU_Target* gpu_screen = NULL; - - GPU_SetRequiredFeatures(GPU_FEATURE_BASIC_SHADERS); - gpu_screen = GPU_InitRenderer(GPU_RENDERER_OPENGL_2, SCREEN_WIDTH, SCREEN_HEIGHT, GPU_DEFAULT_INIT_FLAGS); - if(gpu_screen == NULL){ - GPU_LogError("Initialization Error: Could not create a renderer with proper feature support for this demo.\n"); - return 1; - } - rtarget.target = gpu_screen; -#else - SDL_Window* window = NULL; - SDL_Surface* screenSurface = NULL; - - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - return 1; - } -// SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); -// SDL_SetHintWithPriority(SDL_HINT_RENDER_SCALE_QUALITY, "0", SDL_HINT_OVERRIDE); - - window = SDL_CreateWindow( - "hello_sdl2", - SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - SCREEN_WIDTH, SCREEN_HEIGHT, - SDL_WINDOW_SHOWN - ); - if (window == NULL) { - fprintf(stderr, "could not create window: %s\n", SDL_GetError()); - return 1; - } - - screenSurface = SDL_GetWindowSurface(window); - if(!screenSurface){ - printf("Error: %s\n",SDL_GetError()); - exit(-1); - } - rtarget.surface = screenSurface; -#endif - data_source_set((DataSource*)mock_data_source_new()); - - hud = basic_hud_new(); - - - SDL_Rect whole = {0,0,SCREEN_WIDTH,SCREEN_HEIGHT}; - -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - - done = false; - Uint32 ticks; - Uint32 last_ticks = 0; - Uint32 elapsed = 0; - Uint32 acc = 0; - i = 3; - do{ - ticks = SDL_GetTicks(); - elapsed = ticks - last_ticks; - acc += elapsed; - - done = handle_events(elapsed); - - /* Not having this in the loop breaks ladder-gauge display - * TODO: Check why and fix - * */ -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - base_gauge_render(BASE_GAUGE(hud), elapsed, &(RenderContext){rtarget, &whole, NULL}); - -#if USE_SDL_GPU - GPU_Flip(gpu_screen); -#else - SDL_UpdateWindowSurface(window); -#endif -#if 1 - if(elapsed < 200){ - SDL_Delay(200 - elapsed); - } -#endif - if(acc >= 10000){ - acc = 0; - } - - last_ticks = ticks; - }while(!done); - - base_gauge_free(BASE_GAUGE(hud)); - resource_manager_shutdown(); - data_source_free(data_source_get_instance()); -#if USE_SDL_GPU - GPU_Quit(); -#else - SDL_DestroyWindow(window); - SDL_Quit(); -#endif - return 0; - -} - diff --git a/testbench/button.c b/testbench/button.c deleted file mode 100644 index 99ae67b..0000000 --- a/testbench/button.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include - -#include -#include - -#include "base-gauge.h" -#include "base-widget.h" -#include "button.h" -#include "data-source.h" - -#include "mock-data-source.h" -#include "resource-manager.h" - -#include "sdl-colors.h" - -#define SCREEN_WIDTH 640 -#define SCREEN_HEIGHT 480 - -//#define SCREEN_WIDTH 800 -//#define SCREEN_HEIGHT 480 - - -Button *btn_flat = NULL; - - -/*Return true to quit the app*/ -bool handle_keyboard(SDL_KeyboardEvent *event, Uint32 elapsed) -{ - if(btn_flat) - base_widget_handle_event(BASE_WIDGET(btn_flat), event); - - if(event->state != SDL_PRESSED) return false; - switch(event->keysym.sym){ - case SDLK_ESCAPE: - return true; - break; - default: - break; - } - - return false; -} - -/*Return true to quit the app*/ -bool handle_events(Uint32 elapsed) -{ - SDL_Event event; - - while(SDL_PollEvent(&event) == 1){ - switch(event.type){ - case SDL_QUIT: - return true; - break; - case SDL_WINDOWEVENT: - if(event.window.event == SDL_WINDOWEVENT_CLOSE) - return true; - break; - case SDL_KEYUP: - case SDL_KEYDOWN: - return handle_keyboard(&(event.key), elapsed); - break; - } - } - return false; -} - - - -int main(int argc, char **argv) -{ - bool done; - int i; - float oldv[5] = {0,0,0,0,0}; - RenderTarget rtarget; - -#if USE_SDL_GPU - GPU_Target* gpu_screen = NULL; - - GPU_SetRequiredFeatures(GPU_FEATURE_BASIC_SHADERS); - gpu_screen = GPU_InitRenderer(GPU_RENDERER_OPENGL_2, SCREEN_WIDTH, SCREEN_HEIGHT, GPU_DEFAULT_INIT_FLAGS); - if(gpu_screen == NULL){ - GPU_LogError("Initialization Error: Could not create a renderer with proper feature support for this demo.\n"); - return 1; - } - rtarget.target = gpu_screen; -#else - SDL_Window* window = NULL; - SDL_Surface* screenSurface = NULL; - - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - return 1; - } -// SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); -// SDL_SetHintWithPriority(SDL_HINT_RENDER_SCALE_QUALITY, "0", SDL_HINT_OVERRIDE); - - window = SDL_CreateWindow( - "hello_sdl2", - SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - SCREEN_WIDTH, SCREEN_HEIGHT, - SDL_WINDOW_SHOWN - ); - if (window == NULL) { - fprintf(stderr, "could not create window: %s\n", SDL_GetError()); - return 1; - } - - screenSurface = SDL_GetWindowSurface(window); - if(!screenSurface){ - printf("Error: %s\n",SDL_GetError()); - exit(-1); - } - rtarget.surface = screenSurface; -#endif - data_source_set((DataSource*)mock_data_source_new()); - -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - - BaseGauge *btn_generic; - /*btn = button_new("Validate", TERMINUS_24, 12*20, 24);*/ - /*btn->alignment = HALIGN_CENTER | VALIGN_MIDDLE;*/ - - //btn_flat = button_new("Validate", TERMINUS_24, SDL_WHITE, SDL_BLACK, 12*20, 27); - /*The following was the original Button size in DirectToDialog*/ - btn_flat = button_new( - "Validate", TERMINUS_24, - SDL_WHITE, SDL_BLACK, - 240, 24 - ); - - BASE_WIDGET(btn_flat)->has_focus = true; - btn_generic = BASE_GAUGE(btn_flat); - - - SDL_Rect btn_rect ={ - 640/2, - 480/2 - 100, - base_gauge_w(BASE_GAUGE(btn_generic)), - base_gauge_h(BASE_GAUGE(btn_generic)) - }; - - - done = false; - Uint32 ticks; - Uint32 last_ticks = 0; - Uint32 elapsed = 0; - Uint32 acc = 0; - i = 3; - do{ - ticks = SDL_GetTicks(); - elapsed = ticks - last_ticks; - acc += elapsed; - - done = handle_events(elapsed); - - /* Not having this in the loop breaks ladder-gauge display - * TODO: Check why and fix - * */ -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - base_gauge_render(btn_generic, elapsed, &(RenderContext){rtarget, &btn_rect, NULL}); - -#if USE_SDL_GPU - GPU_Flip(gpu_screen); -#else - SDL_UpdateWindowSurface(window); -#endif -#if 1 - if(elapsed < 200){ - SDL_Delay(200 - elapsed); - } -#endif - if(acc >= 10000){ - acc = 0; - } - - last_ticks = ticks; - }while(!done); - - base_gauge_free(BASE_GAUGE(btn_generic)); - resource_manager_shutdown(); - data_source_free(data_source_get_instance()); -#if USE_SDL_GPU - GPU_Quit(); -#else - SDL_DestroyWindow(window); - SDL_Quit(); -#endif - return 0; - -} - diff --git a/testbench/compass.c b/testbench/compass.c deleted file mode 100644 index 6c09fb4..0000000 --- a/testbench/compass.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include - -#include -#include - -#include "base-gauge.h" -#include "compass-gauge.h" -#include "data-source.h" - -#include "mock-data-source.h" -#include "resource-manager.h" - -#define SCREEN_WIDTH 640 -#define SCREEN_HEIGHT 480 - -//#define SCREEN_WIDTH 800 -//#define SCREEN_HEIGHT 480 - -CompassGauge *compass = NULL; - -float heading = 0.0; - -#define HEADING_INC 5.0; - - -/*Return true to quit the app*/ -bool handle_keyboard(SDL_KeyboardEvent *event, Uint32 elapsed) -{ - - if(event->state != SDL_PRESSED) return false; - switch(event->keysym.sym){ - case SDLK_ESCAPE: - return true; - break; - case SDLK_e: - heading += HEADING_INC; - heading = fmod(heading, 360.0); - if(heading < 0) - heading += 360.0; - compass_gauge_set_value(compass, heading, true); - break; - case SDLK_SPACE: - printf("heading is: %f\n", heading); - break; - default: - break; - } - - return false; -} - -/*Return true to quit the app*/ -bool handle_events(Uint32 elapsed) -{ - SDL_Event event; - - while(SDL_PollEvent(&event) == 1){ - switch(event.type){ - case SDL_QUIT: - return true; - break; - case SDL_WINDOWEVENT: - if(event.window.event == SDL_WINDOWEVENT_CLOSE) - return true; - break; - case SDL_KEYUP: - case SDL_KEYDOWN: - return handle_keyboard(&(event.key), elapsed); - break; - } - } - return false; -} - - -int main(int argc, char **argv) -{ - bool done; - int i; - float oldv[5] = {0,0,0,0,0}; - RenderTarget rtarget; - -#if USE_SDL_GPU - GPU_Target* gpu_screen = NULL; - - GPU_SetRequiredFeatures(GPU_FEATURE_BASIC_SHADERS); - gpu_screen = GPU_InitRenderer(GPU_RENDERER_OPENGL_2, SCREEN_WIDTH, SCREEN_HEIGHT, GPU_DEFAULT_INIT_FLAGS); - if(gpu_screen == NULL){ - GPU_LogError("Initialization Error: Could not create a renderer with proper feature support for this demo.\n"); - return 1; - } - rtarget.target = gpu_screen; -#else - SDL_Window* window = NULL; - SDL_Surface* screenSurface = NULL; - - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - return 1; - } -// SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); -// SDL_SetHintWithPriority(SDL_HINT_RENDER_SCALE_QUALITY, "0", SDL_HINT_OVERRIDE); - - window = SDL_CreateWindow( - "hello_sdl2", - SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - SCREEN_WIDTH, SCREEN_HEIGHT, - SDL_WINDOW_SHOWN - ); - if (window == NULL) { - fprintf(stderr, "could not create window: %s\n", SDL_GetError()); - return 1; - } - - screenSurface = SDL_GetWindowSurface(window); - if(!screenSurface){ - printf("Error: %s\n",SDL_GetError()); - exit(-1); - } - rtarget.surface = screenSurface; -#endif - data_source_set((DataSource*)mock_data_source_new()); - - compass = compass_gauge_new(); - - SDL_Rect center_rect = {(640-1)/2,(480-1)/2,0,0}; - -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - - done = false; - Uint32 ticks; - Uint32 last_ticks = 0; - Uint32 elapsed = 0; - Uint32 acc = 0; - i = 3; - do{ - ticks = SDL_GetTicks(); - elapsed = ticks - last_ticks; - acc += elapsed; - - done = handle_events(elapsed); - - /* Not having this in the loop breaks ladder-gauge display - * TODO: Check why and fix - * */ -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - base_gauge_render(BASE_GAUGE(compass), elapsed, &(RenderContext){rtarget, ¢er_rect, NULL}); - -#if USE_SDL_GPU - GPU_Flip(gpu_screen); -#else - SDL_UpdateWindowSurface(window); -#endif -#if 1 - if(elapsed < 200){ - SDL_Delay(200 - elapsed); - } -#endif - if(acc >= 10000){ - acc = 0; - } - - last_ticks = ticks; - }while(!done); - - base_gauge_free(BASE_GAUGE(compass)); - resource_manager_shutdown(); - data_source_free(data_source_get_instance()); -#if USE_SDL_GPU - GPU_Quit(); -#else - SDL_DestroyWindow(window); - SDL_Quit(); -#endif - return 0; -} - diff --git a/testbench/direct-to.c b/testbench/direct-to.c deleted file mode 100644 index f8c6945..0000000 --- a/testbench/direct-to.c +++ /dev/null @@ -1,187 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include -#include - -#include -#include - -#include "base-gauge.h" -#include "base-widget.h" -#include "direct-to-dialog.h" -#include "mock-data-source.h" - - -#define SCREEN_WIDTH 640 -#define SCREEN_HEIGHT 480 - - -#define WINDOW_TITLE "Direct To Dialog Test" - -#define N_COLORS 4 - - -DirectToDialog *direct = NULL; - - - - -/*Return true to quit the app*/ -bool handle_keyboard(SDL_KeyboardEvent *event, Uint32 elapsed) -{ - - if(event->state != SDL_PRESSED) return false; - switch(event->keysym.sym){ - case SDLK_ESCAPE: - return true; - break; - - } - if(direct->visible) - base_widget_handle_event(BASE_WIDGET(direct), event); - - - return false; -} - -/*Return true to quit the app*/ -bool handle_events(Uint32 elapsed) -{ - SDL_Event event; - - while(SDL_PollEvent(&event) == 1){ - switch(event.type){ - case SDL_QUIT: - return true; - break; - case SDL_WINDOWEVENT: - if(event.window.event == SDL_WINDOWEVENT_CLOSE) - return true; - break; - case SDL_KEYUP: - case SDL_KEYDOWN: - return handle_keyboard(&(event.key), elapsed); - break; - } - } - return false; -} - - - -int main(int argc, char **argv) -{ - bool done; - float oldv[5] = {0,0,0,0,0}; - RenderTarget rtarget; - -#if USE_SDL_GPU - GPU_Target* gpu_screen = NULL; - - GPU_SetRequiredFeatures(GPU_FEATURE_BASIC_SHADERS); - gpu_screen = GPU_InitRenderer(GPU_RENDERER_OPENGL_2, SCREEN_WIDTH, SCREEN_HEIGHT, GPU_DEFAULT_INIT_FLAGS); - if(gpu_screen == NULL){ - GPU_LogError("Initialization Error: Could not create a renderer with proper feature support for this demo.\n"); - return 1; - } - rtarget.target = gpu_screen; -#else - SDL_Window* window = NULL; - SDL_Surface* screenSurface = NULL; - - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - return 1; - } -// SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); -// SDL_SetHintWithPriority(SDL_HINT_RENDER_SCALE_QUALITY, "0", SDL_HINT_OVERRIDE); - - window = SDL_CreateWindow( - WINDOW_TITLE, - SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - SCREEN_WIDTH, SCREEN_HEIGHT, - SDL_WINDOW_SHOWN - ); - if (window == NULL) { - fprintf(stderr, "could not create window: %s\n", SDL_GetError()); - return 1; - } - - screenSurface = SDL_GetWindowSurface(window); - if(!screenSurface){ - printf("Error: %s\n",SDL_GetError()); - exit(-1); - } - rtarget.surface = screenSurface; -#endif - data_source_set((DataSource*)mock_data_source_new()); - - -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - direct = direct_to_dialog_new(); - SDL_Rect direct_rect ={ - 640/2, - 480/2 - 100, - base_gauge_w(BASE_GAUGE(direct)), - base_gauge_h(BASE_GAUGE(direct)) - }; - direct->visible = true; - - - done = false; - Uint32 ticks; - Uint32 last_ticks = 0; - Uint32 elapsed = 0; - Uint32 acc = 0; - do{ - ticks = SDL_GetTicks(); - elapsed = ticks - last_ticks; - acc += elapsed; - - done = handle_events(elapsed); - - /* Not having this in the loop breaks ladder-gauge display - * TODO: Check why and fix - * */ -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - if(direct->visible) - base_gauge_render(BASE_GAUGE(direct), elapsed, &(RenderContext){rtarget, &direct_rect, NULL}); -#if USE_SDL_GPU - GPU_Flip(gpu_screen); -#else - SDL_UpdateWindowSurface(window); -#endif -#if 1 - if(elapsed < 200){ - SDL_Delay(200 - elapsed); - } -#endif - last_ticks = ticks; - }while(!done); - - base_gauge_free(BASE_GAUGE(direct)); - resource_manager_shutdown(); - data_source_free(data_source_get_instance()); -#if USE_SDL_GPU - GPU_Quit(); -#else - SDL_DestroyWindow(window); - SDL_Quit(); -#endif - return 0; -} - diff --git a/testbench/elevator.c b/testbench/elevator.c deleted file mode 100644 index d2769d7..0000000 --- a/testbench/elevator.c +++ /dev/null @@ -1,226 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include - -#include -#include - -#include "base-gauge.h" -#include "data-source.h" -#include "elevator-gauge.h" - -#include "mock-data-source.h" -#include "resource-manager.h" - -#include "sdl-colors.h" - -#define SCREEN_WIDTH 640 -#define SCREEN_HEIGHT 480 - -//#define SCREEN_WIDTH 800 -//#define SCREEN_HEIGHT 480 - - -ElevatorGauge *elevator = NULL; - -float eleval = 0.0; - -#define ELEVAL_INC 100.0; - - -/*Return true to quit the app*/ -bool handle_keyboard(SDL_KeyboardEvent *event, Uint32 elapsed) -{ - - if(event->state != SDL_PRESSED) return false; - switch(event->keysym.sym){ - case SDLK_ESCAPE: - return true; - break; - case SDLK_j: - if(eleval < elevator->ruler.end){ - eleval += ELEVAL_INC; - elevator_gauge_set_value(elevator, eleval, true); - } - break; - case SDLK_k: - if(eleval > elevator->ruler.start){ - eleval -= ELEVAL_INC; - elevator_gauge_set_value(elevator, eleval, true); - } - break; - case SDLK_SPACE: - printf("Eleval is: %f\n", eleval); - break; - default:{ - } - } - - return false; -} - -/*Return true to quit the app*/ -bool handle_events(Uint32 elapsed) -{ - SDL_Event event; - - while(SDL_PollEvent(&event) == 1){ - switch(event.type){ - case SDL_QUIT: - return true; - break; - case SDL_WINDOWEVENT: - if(event.window.event == SDL_WINDOWEVENT_CLOSE) - return true; - break; - case SDL_KEYUP: - case SDL_KEYDOWN: - return handle_keyboard(&(event.key), elapsed); - break; - } - } - return false; -} - - - -int main(int argc, char **argv) -{ - bool done; - int i; - float oldv[5] = {0,0,0,0,0}; - RenderTarget rtarget; - -#if USE_SDL_GPU - GPU_Target* gpu_screen = NULL; - - GPU_SetRequiredFeatures(GPU_FEATURE_BASIC_SHADERS); - gpu_screen = GPU_InitRenderer(GPU_RENDERER_OPENGL_2, SCREEN_WIDTH, SCREEN_HEIGHT, GPU_DEFAULT_INIT_FLAGS); - if(gpu_screen == NULL){ - GPU_LogError("Initialization Error: Could not create a renderer with proper feature support for this demo.\n"); - return 1; - } - rtarget.target = gpu_screen; -#else - SDL_Window* window = NULL; - SDL_Surface* screenSurface = NULL; - - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - return 1; - } -// SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); -// SDL_SetHintWithPriority(SDL_HINT_RENDER_SCALE_QUALITY, "0", SDL_HINT_OVERRIDE); - - window = SDL_CreateWindow( - "hello_sdl2", - SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - SCREEN_WIDTH, SCREEN_HEIGHT, - SDL_WINDOW_SHOWN - ); - if (window == NULL) { - fprintf(stderr, "could not create window: %s\n", SDL_GetError()); - return 1; - } - - screenSurface = SDL_GetWindowSurface(window); - if(!screenSurface){ - printf("Error: %s\n",SDL_GetError()); - exit(-1); - } - rtarget.surface = screenSurface; -#endif - data_source_set((DataSource*)mock_data_source_new()); - - elevator = elevator_gauge_new( - true, Left, - resource_manager_get_font(TERMINUS_12), - SDL_WHITE, - 300, 2700, 300, - 20, 120, /* 10x60 on the screenshot */ - 3,(ColorZone[]){{ - .from = 300, - .to = 900, - .color = SDL_GREEN, - .flags = FromIncluded | ToIncluded - },{ - .from = 900, - .to = 2000, - .color = SDL_YELLOW, - .flags = FromExcluded | ToIncluded - },{ - .from = 2000, - .to = 2700, - .color = SDL_RED, - .flags = FromExcluded | ToIncluded - }} - ); - - - SDL_Rect center_rect = {(640-1)/2,(480-1)/2,0,0}; - -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - done = false; - Uint32 ticks; - Uint32 last_ticks = 0; - Uint32 elapsed = 0; - Uint32 acc = 0; - i = 3; - do{ - ticks = SDL_GetTicks(); - elapsed = ticks - last_ticks; - acc += elapsed; - - done = handle_events(elapsed); - - /* Not having this in the loop breaks ladder-gauge display - * TODO: Check why and fix - * */ -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - base_gauge_render(BASE_GAUGE(elevator), elapsed, &(RenderContext){rtarget, ¢er_rect, NULL}); - -#if USE_SDL_GPU - GPU_Flip(gpu_screen); -#else - SDL_UpdateWindowSurface(window); -#endif -#if 1 - if(elapsed < 200){ - SDL_Delay(200 - elapsed); - } -#endif - if(acc >= 10000){ - acc = 0; - } - - last_ticks = ticks; - }while(!done); - - base_gauge_free(BASE_GAUGE(elevator)); - resource_manager_shutdown(); - data_source_free(data_source_get_instance()); -#if USE_SDL_GPU - GPU_Quit(); -#else - SDL_DestroyWindow(window); - SDL_Quit(); -#endif - return 0; - -} - diff --git a/testbench/fish.c b/testbench/fish.c deleted file mode 100644 index 71b0c21..0000000 --- a/testbench/fish.c +++ /dev/null @@ -1,229 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include - -#include -#include - -#include "base-gauge.h" -#include "data-source.h" -#include "fishbone-gauge.h" - -#include "mock-data-source.h" -#include "resource-manager.h" - -#include "sdl-colors.h" - -#define SCREEN_WIDTH 640 -#define SCREEN_HEIGHT 480 - -//#define SCREEN_WIDTH 800 -//#define SCREEN_HEIGHT 480 - - -FishboneGauge *fish = NULL; - -float fishval = 0.0; - -#define FISHVAL_INC 1.0; - - - - -/*Return true to quit the app*/ -bool handle_keyboard(SDL_KeyboardEvent *event, Uint32 elapsed) -{ - - if(event->state != SDL_PRESSED) return false; - switch(event->keysym.sym){ - case SDLK_ESCAPE: - return true; - break; - case SDLK_y: - if(fishval < fish->ruler.end){ - fishval += FISHVAL_INC; - fishbone_gauge_set_value(fish, fishval, true); - } - break; - case SDLK_h: - if(fishval > fish->ruler.start){ - fishval -= FISHVAL_INC; - fishbone_gauge_set_value(fish, fishval, true); - } - break; - case SDLK_SPACE: - printf("Fishval is: %f\n", fishval); - break; - default:{ - } - } - - return false; -} - -/*Return true to quit the app*/ -bool handle_events(Uint32 elapsed) -{ - SDL_Event event; - - while(SDL_PollEvent(&event) == 1){ - switch(event.type){ - case SDL_QUIT: - return true; - break; - case SDL_WINDOWEVENT: - if(event.window.event == SDL_WINDOWEVENT_CLOSE) - return true; - break; - case SDL_KEYUP: - case SDL_KEYDOWN: - return handle_keyboard(&(event.key), elapsed); - break; - } - } - return false; -} - - - -int main(int argc, char **argv) -{ - bool done; - int i; - float oldv[5] = {0,0,0,0,0}; - RenderTarget rtarget; - -#if USE_SDL_GPU - GPU_Target* gpu_screen = NULL; - - GPU_SetRequiredFeatures(GPU_FEATURE_BASIC_SHADERS); - gpu_screen = GPU_InitRenderer(GPU_RENDERER_OPENGL_2, SCREEN_WIDTH, SCREEN_HEIGHT, GPU_DEFAULT_INIT_FLAGS); - if(gpu_screen == NULL){ - GPU_LogError("Initialization Error: Could not create a renderer with proper feature support for this demo.\n"); - return 1; - } - rtarget.target = gpu_screen; -#else - SDL_Window* window = NULL; - SDL_Surface* screenSurface = NULL; - - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - return 1; - } -// SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); -// SDL_SetHintWithPriority(SDL_HINT_RENDER_SCALE_QUALITY, "0", SDL_HINT_OVERRIDE); - - window = SDL_CreateWindow( - "hello_sdl2", - SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - SCREEN_WIDTH, SCREEN_HEIGHT, - SDL_WINDOW_SHOWN - ); - if (window == NULL) { - fprintf(stderr, "could not create window: %s\n", SDL_GetError()); - return 1; - } - - screenSurface = SDL_GetWindowSurface(window); - if(!screenSurface){ - printf("Error: %s\n",SDL_GetError()); - exit(-1); - } - rtarget.surface = screenSurface; -#endif - data_source_set((DataSource*)mock_data_source_new()); - - fish = fishbone_gauge_new( - true, - resource_manager_get_font(TERMINUS_12), - SDL_WHITE, - 0, 25, 5, - 150, 13, /* 76x9 on the screenshot*/ - 3,(ColorZone[]){{ - .from = 0, - .to = 2, - .color = SDL_RED, - .flags = FromIncluded | ToIncluded - },{ - .from = 2, - .to = 10, - .color = SDL_YELLOW, - .flags = FromExcluded | ToIncluded - - },{ - .from = 10, - .to = 25, - .color = SDL_GREEN, - .flags = FromExcluded | ToIncluded - }} - ); - - - SDL_Rect center_rect = {(640-1)/2,(480-1)/2,0,0}; - -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - done = false; - Uint32 ticks; - Uint32 last_ticks = 0; - Uint32 elapsed = 0; - Uint32 acc = 0; - i = 3; - do{ - ticks = SDL_GetTicks(); - elapsed = ticks - last_ticks; - acc += elapsed; - - done = handle_events(elapsed); - - /* Not having this in the loop breaks ladder-gauge display - * TODO: Check why and fix - * */ -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - base_gauge_render(BASE_GAUGE(fish), elapsed, &(RenderContext){rtarget, ¢er_rect, NULL}); - -#if USE_SDL_GPU - GPU_Flip(gpu_screen); -#else - SDL_UpdateWindowSurface(window); -#endif -#if 1 - if(elapsed < 200){ - SDL_Delay(200 - elapsed); - } -#endif - if(acc >= 10000){ - acc = 0; - } - - last_ticks = ticks; - }while(!done); - - base_gauge_free(BASE_GAUGE(fish)); - resource_manager_shutdown(); - data_source_free(data_source_get_instance()); -#if USE_SDL_GPU - GPU_Quit(); -#else - SDL_DestroyWindow(window); - SDL_Quit(); -#endif - return 0; - -} - diff --git a/testbench/ladder.c b/testbench/ladder.c deleted file mode 100644 index a4c3319..0000000 --- a/testbench/ladder.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include - -#include -#include - -#include "base-gauge.h" -#include "base-widget.h" -#include "softkey.h" -#include "ladder-gauge.h" -#include "alt-ladder-page-descriptor.h" - - -#define SCREEN_WIDTH 640 -#define SCREEN_HEIGHT 480 - -//#define SCREEN_WIDTH 800 -//#define SCREEN_HEIGHT 480 - -LadderGauge *ladder = NULL; - -float alt = 900.0; - -#define ALT_INC 150 - - -//typedef void (*EventListenerFunc)(void *self, BaseWidget *sender); -void button_soft_key_listener(EventListener *self, Softkey *sender) -{ - if(sender->state == SOFTKEY_STATE_RELEASED) - softkey_set_state(sender, SOFTKEY_STATE_PRESSED); - else - softkey_set_state(sender, SOFTKEY_STATE_RELEASED); -} - -/*Return true to quit the app*/ -bool handle_keyboard(SDL_KeyboardEvent *event, Uint32 elapsed) -{ - - if(event->state != SDL_PRESSED) return false; - switch(event->keysym.sym){ - case SDLK_ESCAPE: - return true; - break; - case SDLK_UP: - alt += ALT_INC; - ladder_gauge_set_value(ladder, alt, true); - break; - case SDLK_DOWN: - alt -= ALT_INC; - ladder_gauge_set_value(ladder, alt, true); - break; - case SDLK_SPACE: - printf("Alt is: %f\n", alt); - break; - default: - break; - } - return false; -} - -/*Return true to quit the app*/ -bool handle_events(Uint32 elapsed) -{ - SDL_Event event; - - while(SDL_PollEvent(&event) == 1){ - switch(event.type){ - case SDL_QUIT: - return true; - break; - case SDL_WINDOWEVENT: - if(event.window.event == SDL_WINDOWEVENT_CLOSE) - return true; - break; - case SDL_KEYUP: - case SDL_KEYDOWN: - return handle_keyboard(&(event.key), elapsed); - break; - } - } - return false; -} - -int main(int argc, char **argv) -{ - bool done; - int i; - float oldv[5] = {0,0,0,0,0}; - RenderTarget rtarget; - -#if USE_SDL_GPU - GPU_Target* gpu_screen = NULL; - - GPU_SetRequiredFeatures(GPU_FEATURE_BASIC_SHADERS); - gpu_screen = GPU_InitRenderer(GPU_RENDERER_OPENGL_2, SCREEN_WIDTH, SCREEN_HEIGHT, GPU_DEFAULT_INIT_FLAGS); - if(gpu_screen == NULL){ - GPU_LogError("Initialization Error: Could not create a renderer with proper feature support for this demo.\n"); - return 1; - } - rtarget.target = gpu_screen; -#else - SDL_Window* window = NULL; - SDL_Surface* screenSurface = NULL; - - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - return 1; - } -// SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); -// SDL_SetHintWithPriority(SDL_HINT_RENDER_SCALE_QUALITY, "0", SDL_HINT_OVERRIDE); - - window = SDL_CreateWindow( - "hello_sdl2", - SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - SCREEN_WIDTH, SCREEN_HEIGHT, - SDL_WINDOW_SHOWN - ); - if (window == NULL) { - fprintf(stderr, "could not create window: %s\n", SDL_GetError()); - return 1; - } - - screenSurface = SDL_GetWindowSurface(window); - if(!screenSurface){ - printf("Error: %s\n",SDL_GetError()); - exit(-1); - } - rtarget.surface = screenSurface; -#endif - - ladder = ladder_gauge_new(68, 240, (LadderPageDescriptor *)alt_ladder_page_descriptor_new(), -1); - ladder_gauge_set_value(ladder, alt, true); - - SDL_Rect lrect = {150,20,0,0}; -// SDL_Rect lrect = {0,0,0,0}; - -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - done = false; - Uint32 ticks; - Uint32 last_ticks = 0; - Uint32 elapsed = 0; - Uint32 acc = 0; - i = 3; - do{ - ticks = SDL_GetTicks(); - elapsed = ticks - last_ticks; - acc += elapsed; - - done = handle_events(elapsed); - - /* Not having this in the loop breaks ladder-gauge display - * TODO: Check why and fix - * */ -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - base_gauge_render(BASE_GAUGE(ladder), elapsed, &(RenderContext){rtarget, &lrect, NULL}); - - -#if USE_SDL_GPU - GPU_Flip(gpu_screen); -#else - SDL_UpdateWindowSurface(window); -#endif -#if 1 - if(elapsed < 200){ - SDL_Delay(200 - elapsed); - } -#endif - if(acc >= 10000){ - /*if(ladder->value != oldv[0]){*/ - /*printf("Ladder value: %f\n",ladder->value);*/ - /*oldv[0] = ladder->value;*/ - /*}*/ - acc = 0; - } - last_ticks = ticks; - }while(!done); - - base_gauge_free(BASE_GAUGE(ladder)); - resource_manager_shutdown(); -#if USE_SDL_GPU - GPU_Quit(); -#else - SDL_DestroyWindow(window); - SDL_Quit(); -#endif - return 0; - -} - diff --git a/testbench/map.c b/testbench/map.c deleted file mode 100644 index 639707a..0000000 --- a/testbench/map.c +++ /dev/null @@ -1,244 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include -#include -#include - -#include -#include - -#include "base-gauge.h" -#include "base-widget.h" -#include "basic-hud.h" -#include "button.h" -#include "softkey.h" -#include "compass-gauge.h" -#include "data-source.h" -#include "elevator-gauge.h" -#include "fishbone-gauge.h" -#include "ladder-gauge.h" -#include "alt-ladder-page-descriptor.h" - -#include "ladder-page.h" -#include "mock-data-source.h" -#include "odo-gauge.h" -#include "alt-indicator.h" -#include "pfd-toplevel-softkey-model.h" -#include "resource-manager.h" -#include "SDL_pcf.h" -#include "side-panel.h" -#include "text-gauge.h" -#include "vertical-stair.h" -#include "alt-group.h" -#include "airspeed-indicator.h" -#include "attitude-indicator.h" -#include "roll-slip-gauge.h" -#include "tape-gauge.h" -#include "map-gauge.h" -#include "route-map-provider.h" -#include "direct-to-dialog.h" -#include "softkey-bar.h" - - -#include "sdl-colors.h" -#include "res-dirs.h" - -#define SCREEN_WIDTH 640 -#define SCREEN_HEIGHT 480 - -//#define SCREEN_WIDTH 800 -//#define SCREEN_HEIGHT 480 - -MapGauge *map = NULL; - - - - - - -/*Return true to quit the app*/ -bool handle_keyboard(SDL_KeyboardEvent *event, Uint32 elapsed) -{ - - if(event->state != SDL_PRESSED) return false; - switch(event->keysym.sym){ - case SDLK_ESCAPE: - return true; - break; - case SDLK_UP: - map_gauge_move_viewport(map, 0, -10, true); - break; - case SDLK_DOWN: - map_gauge_move_viewport(map, 0, 10, true); - break; - case SDLK_LEFT: - map_gauge_move_viewport(map, -10, 0, true); - break; - case SDLK_RIGHT: - map_gauge_move_viewport(map, 10, 0, true); - break; - case SDLK_KP_PLUS: - map_gauge_set_level(map, map->level+1); - break; - case SDLK_KP_MINUS: - map_gauge_set_level(map, map->level-1); - break; - default: - break; - } - - return false; -} - -/*Return true to quit the app*/ -bool handle_events(Uint32 elapsed) -{ - SDL_Event event; - - while(SDL_PollEvent(&event) == 1){ - switch(event.type){ - case SDL_QUIT: - return true; - break; - case SDL_WINDOWEVENT: - if(event.window.event == SDL_WINDOWEVENT_CLOSE) - return true; - break; - case SDL_KEYUP: - case SDL_KEYDOWN: - return handle_keyboard(&(event.key), elapsed); - break; - } - } - return false; -} - - - -int main(int argc, char **argv) -{ - bool done; - int i; - float oldv[5] = {0,0,0,0,0}; - RenderTarget rtarget; - -#if USE_SDL_GPU - GPU_Target* gpu_screen = NULL; - - GPU_SetRequiredFeatures(GPU_FEATURE_BASIC_SHADERS); - gpu_screen = GPU_InitRenderer(GPU_RENDERER_OPENGL_2, SCREEN_WIDTH, SCREEN_HEIGHT, GPU_DEFAULT_INIT_FLAGS); - if(gpu_screen == NULL){ - GPU_LogError("Initialization Error: Could not create a renderer with proper feature support for this demo.\n"); - return 1; - } - rtarget.target = gpu_screen; -#else - SDL_Window* window = NULL; - SDL_Surface* screenSurface = NULL; - - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - return 1; - } -// SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); -// SDL_SetHintWithPriority(SDL_HINT_RENDER_SCALE_QUALITY, "0", SDL_HINT_OVERRIDE); - - window = SDL_CreateWindow( - "hello_sdl2", - SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - SCREEN_WIDTH, SCREEN_HEIGHT, - SDL_WINDOW_SHOWN - ); - if (window == NULL) { - fprintf(stderr, "could not create window: %s\n", SDL_GetError()); - return 1; - } - - screenSurface = SDL_GetWindowSurface(window); - if(!screenSurface){ - printf("Error: %s\n",SDL_GetError()); - exit(-1); - } - rtarget.surface = screenSurface; -#endif - data_source_set((DataSource*)mock_data_source_new()); - - map = map_gauge_new(128,128); - map->level = 7; -// map_gauge_set_marker_position(map, 45.21749913, 5.84249663); - map_gauge_set_marker_position(map, 43.32066538, 3.35199859); - map_gauge_center_on_marker(map, true); - route_map_provider_set_route(map->route_overlay, - &(GeoLocation){43.32066538, 3.35199859}, - &(GeoLocation){47.06086, 2.37017} - ); - - - SDL_Rect center_rect = {(640-1)/2,(480-1)/2,0,0}; - -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - - done = false; - Uint32 ticks; - Uint32 last_ticks = 0; - Uint32 elapsed = 0; - Uint32 acc = 0; - i = 3; - do{ - ticks = SDL_GetTicks(); - elapsed = ticks - last_ticks; - acc += elapsed; - - done = handle_events(elapsed); - - /* Not having this in the loop breaks ladder-gauge display - * TODO: Check why and fix - * */ -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - base_gauge_render(BASE_GAUGE(map), elapsed, &(RenderContext){rtarget, ¢er_rect, NULL}); - -#if USE_SDL_GPU - GPU_Flip(gpu_screen); -#else - SDL_UpdateWindowSurface(window); -#endif -#if 1 - if(elapsed < 200){ - SDL_Delay(200 - elapsed); - } -#endif - if(acc >= 10000){ - acc = 0; - } - - last_ticks = ticks; - }while(!done); - - base_gauge_free(BASE_GAUGE(map)); - resource_manager_shutdown(); - data_source_free(data_source_get_instance()); -#if USE_SDL_GPU - GPU_Quit(); -#else - SDL_DestroyWindow(window); - SDL_Quit(); -#endif - return 0; - -} - diff --git a/testbench/odometer.c b/testbench/odometer.c deleted file mode 100644 index 4c0a19f..0000000 --- a/testbench/odometer.c +++ /dev/null @@ -1,282 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include - -#include -#include - -#include "base-gauge.h" -#include "odo-gauge.h" -#include "data-source.h" - -#include "mock-data-source.h" -#include "resource-manager.h" -#include "SDL_pcf.h" - - - -#define SCREEN_WIDTH 640 -#define SCREEN_HEIGHT 480 - -//#define SCREEN_WIDTH 800 -//#define SCREEN_HEIGHT 480 - - -OdoGauge *gauge = NULL; -OdoGauge *wheel = NULL; -OdoGauge *odo = NULL; - -float gval = 0.0; -float alt = 900.0; -float odo_val = 0.0; - -#define GVAL_INC 10.0; -#define ODO_INC 1 -#define ALT_INC 150 - - - -/*Return true to quit the app*/ -bool handle_keyboard(SDL_KeyboardEvent *event, Uint32 elapsed) -{ - - - if(event->state != SDL_PRESSED) return false; - switch(event->keysym.sym){ - case SDLK_ESCAPE: - return true; - break; - case SDLK_t: - gval += GVAL_INC; - if(gval > 99) - gval = 99; - odo_gauge_set_value(gauge, gval, true); - printf("Odo gauge just set to %0.2f\n",gval); - break; - case SDLK_g: - gval -= GVAL_INC; - if(gval < 0) - gval = 0; - odo_gauge_set_value(gauge, gval, true); - printf("Odo gauge just set to %0.2f\n",gval); - break; - case SDLK_UP: - alt += ALT_INC; - odo_gauge_set_value(wheel, alt, true); - break; - case SDLK_DOWN: - alt -= ALT_INC; - odo_gauge_set_value(wheel, alt, true); - break; - case SDLK_l: - odo_gauge_set_value(wheel, 300, true); - break; - case SDLK_PAGEUP: - if(odo_val < odo->max_value) - odo_val += ODO_INC; - odo_gauge_set_value(odo, odo_val, true); - odo_gauge_set_value(gauge, odo_val, true); - break; - case SDLK_PAGEDOWN: - if(odo_val > 0.0) - odo_val -= ODO_INC; - odo_gauge_set_value(odo, odo_val, true); - odo_gauge_set_value(gauge, odo_val, true); - break; - case SDLK_SPACE: - printf("Alt is: %f\n", alt); - break; - default: - break; - } - return false; -} - -/*Return true to quit the app*/ -bool handle_events(Uint32 elapsed) -{ - SDL_Event event; - - while(SDL_PollEvent(&event) == 1){ - switch(event.type){ - case SDL_QUIT: - return true; - break; - case SDL_WINDOWEVENT: - if(event.window.event == SDL_WINDOWEVENT_CLOSE) - return true; - break; - case SDL_KEYUP: - case SDL_KEYDOWN: - return handle_keyboard(&(event.key), elapsed); - break; - } - } - return false; -} - - -int main(int argc, char **argv) -{ - bool done; - int i; - float oldv[5] = {0,0,0,0,0}; - RenderTarget rtarget; - -#if USE_SDL_GPU - GPU_Target* gpu_screen = NULL; - - GPU_SetRequiredFeatures(GPU_FEATURE_BASIC_SHADERS); - gpu_screen = GPU_InitRenderer(GPU_RENDERER_OPENGL_2, SCREEN_WIDTH, SCREEN_HEIGHT, GPU_DEFAULT_INIT_FLAGS); - if(gpu_screen == NULL){ - GPU_LogError("Initialization Error: Could not create a renderer with proper feature support for this demo.\n"); - return 1; - } - rtarget.target = gpu_screen; -#else - SDL_Window* window = NULL; - SDL_Surface* screenSurface = NULL; - - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - return 1; - } -// SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); -// SDL_SetHintWithPriority(SDL_HINT_RENDER_SCALE_QUALITY, "0", SDL_HINT_OVERRIDE); - - window = SDL_CreateWindow( - "hello_sdl2", - SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - SCREEN_WIDTH, SCREEN_HEIGHT, - SDL_WINDOW_SHOWN - ); - if (window == NULL) { - fprintf(stderr, "could not create window: %s\n", SDL_GetError()); - return 1; - } - - screenSurface = SDL_GetWindowSurface(window); - if(!screenSurface){ - printf("Error: %s\n",SDL_GetError()); - exit(-1); - } - rtarget.surface = screenSurface; -#endif - data_source_set((DataSource*)mock_data_source_new()); - gauge = odo_gauge_new(digit_barrel_new( - resource_manager_get_font(TERMINUS_32), 0, 99,10), - -1,-1 - ); - odo_gauge_set_value(gauge, gval, true); - - - PCF_Font *fnt = resource_manager_get_font(TERMINUS_18); - DigitBarrel *db = digit_barrel_new(fnt, 0, 9.999, 1); - DigitBarrel *db2 = digit_barrel_new(fnt, 0, 99, 10); - wheel = odo_gauge_new_multiple(-1, 4, - -1, db2, - -2, db, - -2, db, - -2, db - ); - odo_gauge_set_value(wheel, alt, true); - - DigitBarrel *db4 = digit_barrel_new(fnt, 0, 9.999, 1); - DigitBarrel *db3 = digit_barrel_new(fnt, 0, 99, 10); - odo = odo_gauge_new_multiple(-1, 3, - -1, db3, - -2, db4, - -2, db4 - ); - odo_gauge_set_value(odo, odo_val, true); - - - - - SDL_Rect dst = {SCREEN_WIDTH/2,SCREEN_HEIGHT/2,0,0}; - SDL_Rect lrect = {150,20,0,0}; -// SDL_Rect lrect = {0,0,0,0}; - SDL_Rect wheelrect = {400,20,0,0}; - SDL_Rect odorect = {SCREEN_WIDTH/2 - 80,SCREEN_HEIGHT/2,0,0}; - - -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - - - - done = false; - Uint32 ticks; - Uint32 last_ticks = 0; - Uint32 elapsed = 0; - Uint32 acc = 0; - i = 3; - do{ - ticks = SDL_GetTicks(); - elapsed = ticks - last_ticks; - acc += elapsed; - - done = handle_events(elapsed); - - /* Not having this in the loop breaks ladder-gauge display - * TODO: Check why and fix - * */ -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - base_gauge_render(BASE_GAUGE(gauge), elapsed, &(RenderContext){rtarget, &dst, NULL}); - base_gauge_render(BASE_GAUGE(wheel), elapsed, &(RenderContext){rtarget, &wheelrect, NULL}); - base_gauge_render(BASE_GAUGE(odo), elapsed, &(RenderContext){rtarget, &odorect, NULL}); - -#if USE_SDL_GPU - GPU_Flip(gpu_screen); -#else - SDL_UpdateWindowSurface(window); -#endif -#if 1 - if(elapsed < 200){ - SDL_Delay(200 - elapsed); - } -#endif - if(acc >= 10000){ - /*if(ANIMATED_GAUGE(gauge)->value != oldv[1]){*/ - /*printf("Rotary gauge value: %f\n",ANIMATED_GAUGE(gauge)->value);*/ - /*oldv[1] = ANIMATED_GAUGE(gauge)->value;*/ - /*}*/ - /*if(ANIMATED_GAUGE(odo)->value != oldv[2]){*/ - /*printf("Odo gauge value: %f\n",ANIMATED_GAUGE(odo)->value);*/ - /*oldv[2] = ANIMATED_GAUGE(odo)->value;*/ - /*}*/ - acc = 0; - } - - last_ticks = ticks; - }while(!done); - - base_gauge_free(BASE_GAUGE(gauge)); - base_gauge_free(BASE_GAUGE(wheel)); - base_gauge_free(BASE_GAUGE(odo)); - resource_manager_shutdown(); - data_source_free(data_source_get_instance()); -#if USE_SDL_GPU - GPU_Quit(); -#else - SDL_DestroyWindow(window); - SDL_Quit(); -#endif - return 0; - -} - diff --git a/testbench/roll-slip.c b/testbench/roll-slip.c deleted file mode 100644 index e5cf775..0000000 --- a/testbench/roll-slip.c +++ /dev/null @@ -1,216 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include - -#include -#include - -#include "base-gauge.h" -#include "data-source.h" - -#include "mock-data-source.h" -#include "resource-manager.h" -#include "roll-slip-gauge.h" - - -#define SCREEN_WIDTH 640 -#define SCREEN_HEIGHT 480 - -//#define SCREEN_WIDTH 800 -//#define SCREEN_HEIGHT 480 - - -RollSlipGauge *rsg = NULL; - -float roll = 0.0; -float slip_deg = 0.0; - -#define ROLL_INC 1; -#define SLIP_INC 5.0; - - - -/*Return true to quit the app*/ -bool handle_keyboard(SDL_KeyboardEvent *event, Uint32 elapsed) -{ - - if(event->state != SDL_PRESSED) return false; - switch(event->keysym.sym){ - case SDLK_ESCAPE: - return true; - break; - case SDLK_c: - roll -= ROLL_INC; - roll_slip_gauge_set_value(rsg, roll, true); - break; - case SDLK_d: - roll += ROLL_INC; - roll_slip_gauge_set_value(rsg, roll, true); - break; - case SDLK_i: - slip_deg -= SLIP_INC; - roll_slip_gauge_set_slip(rsg, slip_deg, true); - break; - case SDLK_o: - slip_deg += SLIP_INC; - roll_slip_gauge_set_slip(rsg, slip_deg, true); - break; - case SDLK_SPACE: - printf("Roll is: %f\n", roll); - break; - default: - break; - } - - return false; -} - -/*Return true to quit the app*/ -bool handle_events(Uint32 elapsed) -{ - SDL_Event event; - - while(SDL_PollEvent(&event) == 1){ - switch(event.type){ - case SDL_QUIT: - return true; - break; - case SDL_WINDOWEVENT: - if(event.window.event == SDL_WINDOWEVENT_CLOSE) - return true; - break; - case SDL_KEYUP: - case SDL_KEYDOWN: - return handle_keyboard(&(event.key), elapsed); - break; - } - } - return false; -} - - -int main(int argc, char **argv) -{ - bool done; - int i; - float oldv[5] = {0,0,0,0,0}; - RenderTarget rtarget; - -#if USE_SDL_GPU - GPU_Target* gpu_screen = NULL; - - GPU_SetRequiredFeatures(GPU_FEATURE_BASIC_SHADERS); - gpu_screen = GPU_InitRenderer(GPU_RENDERER_OPENGL_2, SCREEN_WIDTH, SCREEN_HEIGHT, GPU_DEFAULT_INIT_FLAGS); - if(gpu_screen == NULL){ - GPU_LogError("Initialization Error: Could not create a renderer with proper feature support for this demo.\n"); - return 1; - } - rtarget.target = gpu_screen; -#else - SDL_Window* window = NULL; - SDL_Surface* screenSurface = NULL; - - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - return 1; - } -// SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); -// SDL_SetHintWithPriority(SDL_HINT_RENDER_SCALE_QUALITY, "0", SDL_HINT_OVERRIDE); - - window = SDL_CreateWindow( - "hello_sdl2", - SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - SCREEN_WIDTH, SCREEN_HEIGHT, - SDL_WINDOW_SHOWN - ); - if (window == NULL) { - fprintf(stderr, "could not create window: %s\n", SDL_GetError()); - return 1; - } - - screenSurface = SDL_GetWindowSurface(window); - if(!screenSurface){ - printf("Error: %s\n",SDL_GetError()); - exit(-1); - } - rtarget.surface = screenSurface; -#endif - data_source_set((DataSource*)mock_data_source_new()); - - rsg = roll_slip_gauge_new(); - roll_slip_gauge_set_value(rsg, roll, true); - - - SDL_Rect dst = {SCREEN_WIDTH/2,SCREEN_HEIGHT/2,0,0}; - -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - done = false; - Uint32 ticks; - Uint32 last_ticks = 0; - Uint32 elapsed = 0; - Uint32 acc = 0; - i = 3; - do{ - ticks = SDL_GetTicks(); - elapsed = ticks - last_ticks; - acc += elapsed; - - done = handle_events(elapsed); - - /* Not having this in the loop breaks ladder-gauge display - * TODO: Check why and fix - * */ -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - base_gauge_render(BASE_GAUGE(rsg), elapsed, &(RenderContext){rtarget, &dst, NULL}); - -#if USE_SDL_GPU - GPU_Flip(gpu_screen); -#else - SDL_UpdateWindowSurface(window); -#endif -#if 1 - if(elapsed < 200){ - SDL_Delay(200 - elapsed); - } -#endif - if(acc >= 10000){ -#if 0 -/* if(ANIMATED_GAUGE(rsg)->value != oldv[4]){*/ - /*printf("roll value: %0.2f\n",ANIMATED_GAUGE(rsg)->value);*/ - /*oldv[4] = ANIMATED_GAUGE(rsg)->value;*/ - /*}*/ -#endif - acc = 0; - } - - last_ticks = ticks; - }while(!done); - - base_gauge_free(BASE_GAUGE(rsg)); - resource_manager_shutdown(); - data_source_free(data_source_get_instance()); -#if USE_SDL_GPU - GPU_Quit(); -#else - SDL_DestroyWindow(window); - SDL_Quit(); -#endif - return 0; - -} - diff --git a/testbench/side-panel.c b/testbench/side-panel.c deleted file mode 100644 index b14df17..0000000 --- a/testbench/side-panel.c +++ /dev/null @@ -1,184 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include - -#include -#include - -#include "base-gauge.h" -#include "data-source.h" - -#include "mock-data-source.h" -#include "resource-manager.h" -#include "side-panel.h" - -#define SCREEN_WIDTH 640 -#define SCREEN_HEIGHT 480 - -//#define SCREEN_WIDTH 800 -//#define SCREEN_HEIGHT 480 - - -SidePanel *panel = NULL; - - -/*Return true to quit the app*/ -bool handle_keyboard(SDL_KeyboardEvent *event, Uint32 elapsed) -{ - - if(event->state != SDL_PRESSED) return false; - switch(event->keysym.sym){ - case SDLK_ESCAPE: - return true; - break; - default: - break; - - } - - return false; -} - -/*Return true to quit the app*/ -bool handle_events(Uint32 elapsed) -{ - SDL_Event event; - - while(SDL_PollEvent(&event) == 1){ - switch(event.type){ - case SDL_QUIT: - return true; - break; - case SDL_WINDOWEVENT: - if(event.window.event == SDL_WINDOWEVENT_CLOSE) - return true; - break; - case SDL_KEYUP: - case SDL_KEYDOWN: - return handle_keyboard(&(event.key), elapsed); - break; - } - } - return false; -} - - - -int main(int argc, char **argv) -{ - bool done; - int i; - float oldv[5] = {0,0,0,0,0}; - RenderTarget rtarget; - -#if USE_SDL_GPU - GPU_Target* gpu_screen = NULL; - - GPU_SetRequiredFeatures(GPU_FEATURE_BASIC_SHADERS); - gpu_screen = GPU_InitRenderer(GPU_RENDERER_OPENGL_2, SCREEN_WIDTH, SCREEN_HEIGHT, GPU_DEFAULT_INIT_FLAGS); - if(gpu_screen == NULL){ - GPU_LogError("Initialization Error: Could not create a renderer with proper feature support for this demo.\n"); - return 1; - } - rtarget.target = gpu_screen; -#else - SDL_Window* window = NULL; - SDL_Surface* screenSurface = NULL; - - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - return 1; - } -// SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); -// SDL_SetHintWithPriority(SDL_HINT_RENDER_SCALE_QUALITY, "0", SDL_HINT_OVERRIDE); - - window = SDL_CreateWindow( - "hello_sdl2", - SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - SCREEN_WIDTH, SCREEN_HEIGHT, - SDL_WINDOW_SHOWN - ); - if (window == NULL) { - fprintf(stderr, "could not create window: %s\n", SDL_GetError()); - return 1; - } - - screenSurface = SDL_GetWindowSurface(window); - if(!screenSurface){ - printf("Error: %s\n",SDL_GetError()); - exit(-1); - } - rtarget.surface = screenSurface; -#endif - data_source_set((DataSource*)mock_data_source_new()); - - - panel = side_panel_new(-1, -1); - - SDL_Rect sprect = {50,0, base_gauge_w(BASE_GAUGE(panel)), base_gauge_h(BASE_GAUGE(panel))}; - -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - - done = false; - Uint32 ticks; - Uint32 last_ticks = 0; - Uint32 elapsed = 0; - Uint32 acc = 0; - i = 3; - do{ - ticks = SDL_GetTicks(); - elapsed = ticks - last_ticks; - acc += elapsed; - - done = handle_events(elapsed); - - /* Not having this in the loop breaks ladder-gauge display - * TODO: Check why and fix - * */ -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - base_gauge_render(BASE_GAUGE(panel), elapsed, &(RenderContext){rtarget, &sprect, NULL}); - -#if USE_SDL_GPU - GPU_Flip(gpu_screen); -#else - SDL_UpdateWindowSurface(window); -#endif -#if 1 - if(elapsed < 200){ - SDL_Delay(200 - elapsed); - } -#endif - if(acc >= 10000){ - acc = 0; - } - - last_ticks = ticks; - }while(!done); - - base_gauge_free(BASE_GAUGE(panel)); - resource_manager_shutdown(); - data_source_free(data_source_get_instance()); -#if USE_SDL_GPU - GPU_Quit(); -#else - SDL_DestroyWindow(window); - SDL_Quit(); -#endif - return 0; - -} - diff --git a/testbench/softkey-bar.c b/testbench/softkey-bar.c deleted file mode 100644 index 7a9e83b..0000000 --- a/testbench/softkey-bar.c +++ /dev/null @@ -1,216 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include - -#include -#include - -#include "base-gauge.h" -#include "base-widget.h" -#include "softkey.h" -#include "data-source.h" - -#include "mock-data-source.h" -#include "pfd-toplevel-softkey-model.h" -#include "resource-manager.h" -#include "softkey-bar.h" - - -#define SCREEN_WIDTH 640 -#define SCREEN_HEIGHT 480 - -//#define SCREEN_WIDTH 800 -//#define SCREEN_HEIGHT 480 - - -SoftkeyBar *bar = NULL; - - - -/*Return true to quit the app*/ -bool handle_keyboard(SDL_KeyboardEvent *event, Uint32 elapsed) -{ - if(bar) - base_widget_handle_event(BASE_WIDGET(bar), event); - - - if(event->state != SDL_PRESSED) return false; - switch(event->keysym.sym){ - case SDLK_ESCAPE: - return true; - break; - default: - break; - } - - return false; -} - -/*Return true to quit the app*/ -bool handle_events(Uint32 elapsed) -{ - SDL_Event event; - - while(SDL_PollEvent(&event) == 1){ - switch(event.type){ - case SDL_QUIT: - return true; - break; - case SDL_WINDOWEVENT: - if(event.window.event == SDL_WINDOWEVENT_CLOSE) - return true; - break; - case SDL_KEYUP: - case SDL_KEYDOWN: - return handle_keyboard(&(event.key), elapsed); - break; - } - } - return false; -} - - -int main(int argc, char **argv) -{ - bool done; - int i; - float oldv[5] = {0,0,0,0,0}; - RenderTarget rtarget; - -#if USE_SDL_GPU - GPU_Target* gpu_screen = NULL; - - GPU_SetRequiredFeatures(GPU_FEATURE_BASIC_SHADERS); - gpu_screen = GPU_InitRenderer(GPU_RENDERER_OPENGL_2, SCREEN_WIDTH, SCREEN_HEIGHT, GPU_DEFAULT_INIT_FLAGS); - if(gpu_screen == NULL){ - GPU_LogError("Initialization Error: Could not create a renderer with proper feature support for this demo.\n"); - return 1; - } - rtarget.target = gpu_screen; -#else - SDL_Window* window = NULL; - SDL_Surface* screenSurface = NULL; - - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - return 1; - } -// SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); -// SDL_SetHintWithPriority(SDL_HINT_RENDER_SCALE_QUALITY, "0", SDL_HINT_OVERRIDE); - - window = SDL_CreateWindow( - "hello_sdl2", - SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - SCREEN_WIDTH, SCREEN_HEIGHT, - SDL_WINDOW_SHOWN - ); - if (window == NULL) { - fprintf(stderr, "could not create window: %s\n", SDL_GetError()); - return 1; - } - - screenSurface = SDL_GetWindowSurface(window); - if(!screenSurface){ - printf("Error: %s\n",SDL_GetError()); - exit(-1); - } - rtarget.surface = screenSurface; -#endif - data_source_set((DataSource*)mock_data_source_new()); - - - - - - - - SDL_Rect dst = {SCREEN_WIDTH/2,SCREEN_HEIGHT/2,0,0}; - SDL_Rect lrect = {150,20,0,0}; -// SDL_Rect lrect = {0,0,0,0}; - SDL_Rect wheelrect = {400,20,0,0}; - SDL_Rect odorect = {SCREEN_WIDTH/2 - 80,SCREEN_HEIGHT/2,0,0}; - SDL_Rect attrect = {0,0,0,0}; - - // SDL_Rect airect = {SCREEN_WIDTH/2 + 90,SCREEN_HEIGHT/2-20,0,0}; - SDL_Rect airect = {439,51,0,0}; - SDL_Rect vrect = {96,68,0,0}; - SDL_Rect whole = {0,0,SCREEN_WIDTH,SCREEN_HEIGHT}; - SDL_Rect center_rect = {(640-1)/2,(480-1)/2,0,0}; -// SDL_Rect center_rect = {0,0,0,0}; - /*SDL_Rect sprect = {50,0, base_gauge_w(BASE_GAUGE(panel)), base_gauge_h(BASE_GAUGE(panel))};*/ - -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - bar = softkey_bar_new(TERMINUS_12, SOFTKEY_MODEL(pfd_toplevel_softkey_model_get_instance())); - SDL_Rect bar_rect = { - 0, - /* I want to *start* at the last pixel and go up so that the base gauge last H pixel - * is at 479. So I have to walk up the height minus one because otherwise the 479 pixel - * whould have been skipped. TODO: Have a set of macros/functions to handle that. Too - * error prone. - * */ - 479-(base_gauge_h(BASE_GAUGE(bar))-1), - base_gauge_w(BASE_GAUGE(bar)), - base_gauge_h(BASE_GAUGE(bar)) - }; - - done = false; - Uint32 ticks; - Uint32 last_ticks = 0; - Uint32 elapsed = 0; - Uint32 acc = 0; - i = 3; - do{ - ticks = SDL_GetTicks(); - elapsed = ticks - last_ticks; - acc += elapsed; - - done = handle_events(elapsed); - - /* Not having this in the loop breaks ladder-gauge display - * TODO: Check why and fix - * */ -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - base_gauge_render(BASE_GAUGE(bar), elapsed, &(RenderContext){rtarget, &bar_rect, NULL}); -#if USE_SDL_GPU - GPU_Flip(gpu_screen); -#else - SDL_UpdateWindowSurface(window); -#endif -#if 1 - if(elapsed < 200){ - SDL_Delay(200 - elapsed); - } -#endif - if(acc >= 10000){ - acc = 0; - } - - last_ticks = ticks; - }while(!done); - - base_gauge_free(BASE_GAUGE(bar)); - resource_manager_shutdown(); - data_source_free(data_source_get_instance()); -#if USE_SDL_GPU - GPU_Quit(); -#else - SDL_DestroyWindow(window); - SDL_Quit(); -#endif - return 0; - -} - diff --git a/testbench/softkey-btn.c b/testbench/softkey-btn.c deleted file mode 100644 index d46ef02..0000000 --- a/testbench/softkey-btn.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include - -#include -#include - -#include "base-gauge.h" -#include "base-widget.h" -#include "button.h" -#include "softkey.h" -#include "data-source.h" - -#include "mock-data-source.h" -#include "resource-manager.h" - -#define SCREEN_WIDTH 640 -#define SCREEN_HEIGHT 480 - -//#define SCREEN_WIDTH 800 -//#define SCREEN_HEIGHT 480 - - -Softkey *btn_sft = NULL; - - -//typedef void (*EventListenerFunc)(void *self, BaseWidget *sender); -void button_soft_key_listener(EventListener *self, Softkey *sender) -{ - if(sender->state == SOFTKEY_STATE_RELEASED) - softkey_set_state(sender, SOFTKEY_STATE_PRESSED); - else - softkey_set_state(sender, SOFTKEY_STATE_RELEASED); -} - -/*Return true to quit the app*/ -bool handle_keyboard(SDL_KeyboardEvent *event, Uint32 elapsed) -{ - if(btn_sft) - base_widget_handle_event(BASE_WIDGET(btn_sft), event); - - if(event->state != SDL_PRESSED) return false; - switch(event->keysym.sym){ - case SDLK_ESCAPE: - return true; - break; - default: - break; - } - - return false; -} - -/*Return true to quit the app*/ -bool handle_events(Uint32 elapsed) -{ - SDL_Event event; - - while(SDL_PollEvent(&event) == 1){ - switch(event.type){ - case SDL_QUIT: - return true; - break; - case SDL_WINDOWEVENT: - if(event.window.event == SDL_WINDOWEVENT_CLOSE) - return true; - break; - case SDL_KEYUP: - case SDL_KEYDOWN: - return handle_keyboard(&(event.key), elapsed); - break; - } - } - return false; -} - - -int main(int argc, char **argv) -{ - bool done; - int i; - float oldv[5] = {0,0,0,0,0}; - RenderTarget rtarget; - -#if USE_SDL_GPU - GPU_Target* gpu_screen = NULL; - - GPU_SetRequiredFeatures(GPU_FEATURE_BASIC_SHADERS); - gpu_screen = GPU_InitRenderer(GPU_RENDERER_OPENGL_2, SCREEN_WIDTH, SCREEN_HEIGHT, GPU_DEFAULT_INIT_FLAGS); - if(gpu_screen == NULL){ - GPU_LogError("Initialization Error: Could not create a renderer with proper feature support for this demo.\n"); - return 1; - } - rtarget.target = gpu_screen; -#else - SDL_Window* window = NULL; - SDL_Surface* screenSurface = NULL; - - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - return 1; - } -// SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); -// SDL_SetHintWithPriority(SDL_HINT_RENDER_SCALE_QUALITY, "0", SDL_HINT_OVERRIDE); - - window = SDL_CreateWindow( - "hello_sdl2", - SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - SCREEN_WIDTH, SCREEN_HEIGHT, - SDL_WINDOW_SHOWN - ); - if (window == NULL) { - fprintf(stderr, "could not create window: %s\n", SDL_GetError()); - return 1; - } - - screenSurface = SDL_GetWindowSurface(window); - if(!screenSurface){ - printf("Error: %s\n",SDL_GetError()); - exit(-1); - } - rtarget.surface = screenSurface; -#endif - data_source_set((DataSource*)mock_data_source_new()); - - BaseGauge *btn_generic; - - btn_sft = softkey_new("Validate", TERMINUS_24, 12*20, 29); - softkey_set_state(btn_sft, SOFTKEY_STATE_PRESSED); - BUTTON(btn_sft)->validated.callback = (EventListenerFunc)button_soft_key_listener; - btn_generic = BASE_GAUGE(btn_sft); - - SDL_Rect btn_rect ={ - 640/2, - 480/2 - 100, - base_gauge_w(BASE_GAUGE(btn_generic)), - base_gauge_h(BASE_GAUGE(btn_generic)) - }; - - - done = false; - Uint32 ticks; - Uint32 last_ticks = 0; - Uint32 elapsed = 0; - Uint32 acc = 0; - i = 3; - do{ - ticks = SDL_GetTicks(); - elapsed = ticks - last_ticks; - acc += elapsed; - - done = handle_events(elapsed); - - /* Not having this in the loop breaks ladder-gauge display - * TODO: Check why and fix - * */ -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - base_gauge_render(btn_generic, elapsed, &(RenderContext){rtarget, &btn_rect, NULL}); - -#if USE_SDL_GPU - GPU_Flip(gpu_screen); -#else - SDL_UpdateWindowSurface(window); -#endif -#if 1 - if(elapsed < 200){ - SDL_Delay(200 - elapsed); - } -#endif - if(acc >= 10000){ - acc = 0; - } - - last_ticks = ticks; - }while(!done); - - base_gauge_free(BASE_GAUGE(btn_generic)); - resource_manager_shutdown(); - data_source_free(data_source_get_instance()); -#if USE_SDL_GPU - GPU_Quit(); -#else - SDL_DestroyWindow(window); - SDL_Quit(); -#endif - return 0; - -} - diff --git a/testbench/tape.c b/testbench/tape.c deleted file mode 100644 index d25069b..0000000 --- a/testbench/tape.c +++ /dev/null @@ -1,277 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include -#include -#include - -#include -#include - -#include "base-gauge.h" -#include "base-widget.h" -#include "basic-hud.h" -#include "button.h" -#include "softkey.h" -#include "compass-gauge.h" -#include "data-source.h" -#include "elevator-gauge.h" -#include "fishbone-gauge.h" -#include "ladder-gauge.h" -#include "alt-ladder-page-descriptor.h" - -#include "ladder-page.h" -#include "mock-data-source.h" -#include "odo-gauge.h" -#include "alt-indicator.h" -#include "pfd-toplevel-softkey-model.h" -#include "resource-manager.h" -#include "SDL_pcf.h" -#include "side-panel.h" -#include "text-gauge.h" -#include "vertical-stair.h" -#include "alt-group.h" -#include "airspeed-indicator.h" -#include "attitude-indicator.h" -#include "roll-slip-gauge.h" -#include "tape-gauge.h" -#include "map-gauge.h" -#include "route-map-provider.h" -#include "direct-to-dialog.h" -#include "softkey-bar.h" - - -#include "sdl-colors.h" -#include "res-dirs.h" - -#define SCREEN_WIDTH 640 -#define SCREEN_HEIGHT 480 - -//#define SCREEN_WIDTH 800 -//#define SCREEN_HEIGHT 480 - - -TapeGauge *tape_gauge = NULL; -TapeGauge *tape_gauge2 = NULL; - - -float alt = 900.0; - -#define ALT_INC 150 - - - -//typedef void (*EventListenerFunc)(void *self, BaseWidget *sender); -void button_soft_key_listener(EventListener *self, Softkey *sender) -{ - if(sender->state == SOFTKEY_STATE_RELEASED) - softkey_set_state(sender, SOFTKEY_STATE_PRESSED); - else - softkey_set_state(sender, SOFTKEY_STATE_RELEASED); -} - -/*Return true to quit the app*/ -bool handle_keyboard(SDL_KeyboardEvent *event, Uint32 elapsed) -{ - - if(event->state != SDL_PRESSED) return false; - switch(event->keysym.sym){ - case SDLK_ESCAPE: - return true; - break; - case SDLK_UP: - alt += ALT_INC; - tape_gauge_set_value(tape_gauge, alt, true); - break; - case SDLK_DOWN: - alt -= ALT_INC; - tape_gauge_set_value(tape_gauge, alt, true); - break; - case SDLK_SPACE: - printf("Alt is: %f\n", alt); - break; - default: - break; - } - - return false; -} - -/*Return true to quit the app*/ -bool handle_events(Uint32 elapsed) -{ - SDL_Event event; - - while(SDL_PollEvent(&event) == 1){ - switch(event.type){ - case SDL_QUIT: - return true; - break; - case SDL_WINDOWEVENT: - if(event.window.event == SDL_WINDOWEVENT_CLOSE) - return true; - break; - case SDL_KEYUP: - case SDL_KEYDOWN: - return handle_keyboard(&(event.key), elapsed); - break; - } - } - return false; -} - - -int main(int argc, char **argv) -{ - bool done; - int i; - float oldv[5] = {0,0,0,0,0}; - RenderTarget rtarget; - -#if USE_SDL_GPU - GPU_Target* gpu_screen = NULL; - - GPU_SetRequiredFeatures(GPU_FEATURE_BASIC_SHADERS); - gpu_screen = GPU_InitRenderer(GPU_RENDERER_OPENGL_2, SCREEN_WIDTH, SCREEN_HEIGHT, GPU_DEFAULT_INIT_FLAGS); - if(gpu_screen == NULL){ - GPU_LogError("Initialization Error: Could not create a renderer with proper feature support for this demo.\n"); - return 1; - } - rtarget.target = gpu_screen; -#else - SDL_Window* window = NULL; - SDL_Surface* screenSurface = NULL; - - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - return 1; - } -// SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); -// SDL_SetHintWithPriority(SDL_HINT_RENDER_SCALE_QUALITY, "0", SDL_HINT_OVERRIDE); - - window = SDL_CreateWindow( - "hello_sdl2", - SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - SCREEN_WIDTH, SCREEN_HEIGHT, - SDL_WINDOW_SHOWN - ); - if (window == NULL) { - fprintf(stderr, "could not create window: %s\n", SDL_GetError()); - return 1; - } - - screenSurface = SDL_GetWindowSurface(window); - if(!screenSurface){ - printf("Error: %s\n",SDL_GetError()); - exit(-1); - } - rtarget.surface = screenSurface; -#endif - data_source_set((DataSource*)mock_data_source_new()); - - - - - - - - - - - - - - - - PCF_Font *fnt = resource_manager_get_font(TERMINUS_18); - DigitBarrel *db = digit_barrel_new(fnt, 0, 9.999, 1); - DigitBarrel *db2 = digit_barrel_new(fnt, 0, 99, 10); - tape_gauge = tape_gauge_new( - 68, 240, - (LadderPageDescriptor*)alt_ladder_page_descriptor_new(), - AlignRight, 0, 4, - -1, db2, - -2, db, - -2, db, - -2, db - ); - - /*fnt = resource_manager_get_font(TERMINUS_18);*/ - /*db = digit_barrel_new(fnt, 0, 9.999, 1);*/ - /*tape_gauge2 = tape_gauge_new(*/ - /*68, 240,*/ - /*(LadderPageDescriptor*)airspeed_page_descriptor_new(50,60,85,155,200),*/ - /*AlignRight, -12, 3,*/ - /*-1, db,*/ - /*-2, db,*/ - /*-2, db*/ - /*);*/ - - - SDL_Rect vrect = {96,68,0,0}; - -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - done = false; - Uint32 ticks; - Uint32 last_ticks = 0; - Uint32 elapsed = 0; - Uint32 acc = 0; - i = 3; - do{ - ticks = SDL_GetTicks(); - elapsed = ticks - last_ticks; - acc += elapsed; - - done = handle_events(elapsed); - - /* Not having this in the loop breaks ladder-gauge display - * TODO: Check why and fix - * */ -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - base_gauge_render(BASE_GAUGE(tape_gauge), elapsed, &(RenderContext){rtarget, &vrect, NULL}); - /*base_gauge_render(BASE_GAUGE(tape_gauge2), elapsed, &(RenderContext){rtarget, &vrect, NULL});*/ - -#if USE_SDL_GPU - GPU_Flip(gpu_screen); -#else - SDL_UpdateWindowSurface(window); -#endif -#if 1 - if(elapsed < 200){ - SDL_Delay(200 - elapsed); - } -#endif - if(acc >= 10000){ - acc = 0; - } - last_ticks = ticks; - }while(!done); - - base_gauge_free(BASE_GAUGE(tape_gauge)); - /*base_gauge_free(BASE_GAUGE(tape_gauge2));*/ - resource_manager_shutdown(); - data_source_free(data_source_get_instance()); -#if USE_SDL_GPU - GPU_Quit(); -#else - SDL_DestroyWindow(window); - SDL_Quit(); -#endif - return 0; - -} - diff --git a/testbench/text.c b/testbench/text.c deleted file mode 100644 index 78f5956..0000000 --- a/testbench/text.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include - -#include -#include - -#include "base-gauge.h" -#include "data-source.h" - -#include "mock-data-source.h" -#include "resource-manager.h" -#include "SDL_pcf.h" -#include "text-gauge.h" - - -#include "sdl-colors.h" - -#define SCREEN_WIDTH 640 -#define SCREEN_HEIGHT 480 - -//#define SCREEN_WIDTH 800 -//#define SCREEN_HEIGHT 480 - -#define N_COLORS 4 - -TextGauge *txt = NULL; - -float alt = 900.0; -char txtbuf[256]; - -#define ALT_INC 150 - - -/*Return true to quit the app*/ -bool handle_keyboard(SDL_KeyboardEvent *event, Uint32 elapsed) -{ - - if(event->state != SDL_PRESSED) return false; - switch(event->keysym.sym){ - case SDLK_ESCAPE: - return true; - break; - case SDLK_UP: - alt += ALT_INC; - sprintf(txtbuf, "Altitude: %0.2f", alt); - text_gauge_set_value(txt, txtbuf); - break; - case SDLK_DOWN: - alt -= ALT_INC; - sprintf(txtbuf, "Altitude: %0.2f", alt); - text_gauge_set_value(txt, txtbuf); - break; - case SDLK_SPACE: - printf("Alt is: %f\n", alt); - printf("TextGauge value: %s\n", txt->value); - break; - default: - break; - } - - return false; -} - -/*Return true to quit the app*/ -bool handle_events(Uint32 elapsed) -{ - SDL_Event event; - - while(SDL_PollEvent(&event) == 1){ - switch(event.type){ - case SDL_QUIT: - return true; - break; - case SDL_WINDOWEVENT: - if(event.window.event == SDL_WINDOWEVENT_CLOSE) - return true; - break; - case SDL_KEYUP: - case SDL_KEYDOWN: - return handle_keyboard(&(event.key), elapsed); - break; - } - } - return false; -} - - -int main(int argc, char **argv) -{ - bool done; - int i; - float oldv[5] = {0,0,0,0,0}; - RenderTarget rtarget; - -#if USE_SDL_GPU - GPU_Target* gpu_screen = NULL; - - GPU_SetRequiredFeatures(GPU_FEATURE_BASIC_SHADERS); - gpu_screen = GPU_InitRenderer(GPU_RENDERER_OPENGL_2, SCREEN_WIDTH, SCREEN_HEIGHT, GPU_DEFAULT_INIT_FLAGS); - if(gpu_screen == NULL){ - GPU_LogError("Initialization Error: Could not create a renderer with proper feature support for this demo.\n"); - return 1; - } - rtarget.target = gpu_screen; -#else - SDL_Window* window = NULL; - SDL_Surface* screenSurface = NULL; - - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - return 1; - } -// SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); -// SDL_SetHintWithPriority(SDL_HINT_RENDER_SCALE_QUALITY, "0", SDL_HINT_OVERRIDE); - - window = SDL_CreateWindow( - "hello_sdl2", - SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - SCREEN_WIDTH, SCREEN_HEIGHT, - SDL_WINDOW_SHOWN - ); - if (window == NULL) { - fprintf(stderr, "could not create window: %s\n", SDL_GetError()); - return 1; - } - - screenSurface = SDL_GetWindowSurface(window); - if(!screenSurface){ - printf("Error: %s\n",SDL_GetError()); - exit(-1); - } - rtarget.surface = screenSurface; -#endif - data_source_set((DataSource*)mock_data_source_new()); - - txt = text_gauge_new("HI THERE", true, 300, 30); -#if 1 - text_gauge_set_static_font(txt, - resource_manager_get_static_font(TERMINUS_24, - &SDL_WHITE, - 3, PCF_ALPHA, PCF_DIGITS, ".:" - ) - ); -#else - text_gauge_set_font(txt, - resource_manager_get_font(TERMINUS_24) - ); -#endif -#if 1 - text_gauge_set_color(txt, SDL_WHITE, TEXT_COLOR); - text_gauge_set_color(txt, SDL_BLACK, BACKGROUND_COLOR); -#else - text_gauge_set_color(txt, SDL_BLACK, TEXT_COLOR); - text_gauge_set_color(txt, SDL_WHITE, BACKGROUND_COLOR); -#endif - txt->alignment = HALIGN_CENTER | VALIGN_MIDDLE; - SDL_Rect txtrect = {SCREEN_WIDTH/2.0, SCREEN_HEIGHT/2.0,0,0}; - -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - done = false; - Uint32 ticks; - Uint32 last_ticks = 0; - Uint32 elapsed = 0; - Uint32 acc = 0; - i = 3; - do{ - ticks = SDL_GetTicks(); - elapsed = ticks - last_ticks; - acc += elapsed; - - done = handle_events(elapsed); - - /* Not having this in the loop breaks ladder-gauge display - * TODO: Check why and fix - * */ -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - base_gauge_render(BASE_GAUGE(txt), elapsed, &(RenderContext){rtarget, &txtrect, NULL}); - -#if USE_SDL_GPU - GPU_Flip(gpu_screen); -#else - SDL_UpdateWindowSurface(window); -#endif -#if 1 - if(elapsed < 200){ - SDL_Delay(200 - elapsed); - } -#endif - if(acc >= 10000){ - acc = 0; - } - - last_ticks = ticks; - }while(!done); - - base_gauge_free(BASE_GAUGE(txt)); - resource_manager_shutdown(); - data_source_free(data_source_get_instance()); -#if USE_SDL_GPU - GPU_Quit(); -#else - SDL_DestroyWindow(window); - SDL_Quit(); -#endif - return 0; - -} - diff --git a/testbench/vertical-speed-indicator.c b/testbench/vertical-speed-indicator.c deleted file mode 100644 index 76f5ec4..0000000 --- a/testbench/vertical-speed-indicator.c +++ /dev/null @@ -1,221 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include -#include - -#include -#include - -#include "base-gauge.h" -#include "base-widget.h" -#include "softkey.h" -#include "data-source.h" - -#include "mock-data-source.h" -#include "resource-manager.h" -#include "vertical-speed-indicator.h" - -#ifndef SCREEN_WIDTH -#define SCREEN_WIDTH 640 -#endif -#define SCREEN_HEIGHT 480 - -//#define SCREEN_WIDTH 800 -//#define SCREEN_HEIGHT 480 - - -VerticalSpeedIndicator *vsi = NULL; - -//float vs = 2000.0; -float vs = 0.0; - -#define VARIO_INC 100 - - - -//typedef void (*EventListenerFunc)(void *self, BaseWidget *sender); -void button_soft_key_listener(EventListener *self, Softkey *sender) -{ - if(sender->state == SOFTKEY_STATE_RELEASED) - softkey_set_state(sender, SOFTKEY_STATE_PRESSED); - else - softkey_set_state(sender, SOFTKEY_STATE_RELEASED); -} - -/*Return true to quit the app*/ -bool handle_keyboard(SDL_KeyboardEvent *event, Uint32 elapsed) -{ - - if(event->state != SDL_PRESSED) return false; - switch(event->keysym.sym){ - case SDLK_ESCAPE: - return true; - break; - case SDLK_UP: - if(vs < vsi->scale.end) - vs += VARIO_INC; - vertical_speed_indicator_set_value(vsi, vs, true); - break; - case SDLK_DOWN: - if(vs > vsi->scale.start) - vs -= VARIO_INC; - vertical_speed_indicator_set_value(vsi, vs, true); - break; - case SDLK_SPACE: - printf("VS is: %f\n", vs); - break; - default: - break; - } - - return false; -} - -/*Return true to quit the app*/ -bool handle_events(Uint32 elapsed) -{ - SDL_Event event; - - while(SDL_PollEvent(&event) == 1){ - switch(event.type){ - case SDL_QUIT: - return true; - break; - case SDL_WINDOWEVENT: - if(event.window.event == SDL_WINDOWEVENT_CLOSE) - return true; - break; - case SDL_KEYUP: - case SDL_KEYDOWN: - return handle_keyboard(&(event.key), elapsed); - break; - } - } - return false; -} - - - -int main(int argc, char **argv) -{ - bool done; - int i; - float oldv[5] = {0,0,0,0,0}; - RenderTarget rtarget; - -#if USE_SDL_GPU - GPU_Target* gpu_screen = NULL; - - GPU_SetRequiredFeatures(GPU_FEATURE_BASIC_SHADERS); - gpu_screen = GPU_InitRenderer(GPU_RENDERER_OPENGL_2, SCREEN_WIDTH, SCREEN_HEIGHT, GPU_DEFAULT_INIT_FLAGS); - if(gpu_screen == NULL){ - GPU_LogError("Initialization Error: Could not create a renderer with proper feature support for this demo.\n"); - return 1; - } - rtarget.target = gpu_screen; -#else - SDL_Window* window = NULL; - SDL_Surface* screenSurface = NULL; - - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - return 1; - } -// SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); -// SDL_SetHintWithPriority(SDL_HINT_RENDER_SCALE_QUALITY, "0", SDL_HINT_OVERRIDE); - - window = SDL_CreateWindow( - "hello_sdl2", - SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - SCREEN_WIDTH, SCREEN_HEIGHT, - SDL_WINDOW_SHOWN - ); - if (window == NULL) { - fprintf(stderr, "could not create window: %s\n", SDL_GetError()); - return 1; - } - - screenSurface = SDL_GetWindowSurface(window); - if(!screenSurface){ - printf("Error: %s\n",SDL_GetError()); - exit(-1); - } - rtarget.surface = screenSurface; -#endif - data_source_set((DataSource*)mock_data_source_new()); - -#if SCREEN_WIDTH == 640 - vsi = vertical_speed_indicator_new(29, 191, TERMINUS_16); -#else - vsi = vertical_speed_indicator_new(46, 317, TERMINUS_22); -#endif - vertical_speed_indicator_set_value(vsi, vs, true); - - SDL_Rect vrect = {96,68,0,0}; - -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - - done = false; - Uint32 ticks; - Uint32 last_ticks = 0; - Uint32 elapsed = 0; - Uint32 acc = 0; - i = 3; - do{ - ticks = SDL_GetTicks(); - elapsed = ticks - last_ticks; - acc += elapsed; - - done = handle_events(elapsed); - - /* Not having this in the loop breaks ladder-gauge display - * TODO: Check why and fix - * */ -#if USE_SDL_GPU - GPU_ClearRGB(gpu_screen, 0x11, 0x56, 0xFF); -#else - SDL_FillRect(screenSurface, NULL, SDL_UFBLUE(screenSurface)); -#endif - - base_gauge_render(BASE_GAUGE(vsi), elapsed, &(RenderContext){rtarget, &vrect, NULL}); - -#if USE_SDL_GPU - GPU_Flip(gpu_screen); -#else - SDL_UpdateWindowSurface(window); -#endif -#if 1 - if(elapsed < 200){ - SDL_Delay(200 - elapsed); - } -#endif - if(acc >= 10000){ - acc = 0; - } - - last_ticks = ticks; - }while(!done); - - base_gauge_free(BASE_GAUGE(vsi)); - resource_manager_shutdown(); - data_source_free(data_source_get_instance()); -#if USE_SDL_GPU - GPU_Quit(); -#else - SDL_DestroyWindow(window); - SDL_Quit(); -#endif - return 0; - -} - diff --git a/text-gauge.c b/text-gauge.c deleted file mode 100644 index 2063061..0000000 --- a/text-gauge.c +++ /dev/null @@ -1,302 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include -#include -#include - -#include "SDL_gpu.h" -#include "SDL_pcf.h" -#include "SDL_pixels.h" -#include "SDL_rect.h" -#include "base-gauge.h" -#include "generic-layer.h" -#include "text-gauge.h" -#include "sdl-colors.h" -#include "misc.h" - -static void text_gauge_update_state(TextGauge *self, Uint32 dt); -static void text_gauge_render(TextGauge *self, Uint32 dt, RenderContext *ctx); -static void *text_gauge_dispose(TextGauge *self); -static BaseGaugeOps text_gauge_ops = { - .render = (RenderFunc)text_gauge_render, - .update_state = (StateUpdateFunc)text_gauge_update_state, - .dispose = (DisposeFunc)text_gauge_dispose -}; - - -TextGauge *text_gauge_new(const char *value, bool outlined, int w, int h) -{ - TextGauge *self; - - self = calloc(1, sizeof(TextGauge)); - if(self){ - if(!text_gauge_init(self, value, outlined, w, h)){ - return base_gauge_free(BASE_GAUGE(self)); - } - } - return self; -} - -TextGauge *text_gauge_init(TextGauge *self, const char *value, bool outlined, int w, int h) -{ - base_gauge_init(BASE_GAUGE(self), - &text_gauge_ops, - w, h - ); - - if(value) - text_gauge_set_value(self, value); - self->outlined = outlined; - return self; -} - -static void *text_gauge_dispose(TextGauge *self) -{ - if(self->value) - free(self->value); - if(self->font.is_static) - PCF_FreeStaticFont(self->font.static_font); - else - PCF_CloseFont(self->font.font); - if(self->state.chars) - free(self->state.chars); -#if USE_SDL_GPU - if(self->buffer) - generic_layer_free(self->buffer); -#endif - - return self; -} - -static void text_gauge_dispose_font(TextGauge *self) -{ - if(!self->font.is_static && self->font.font){ - PCF_FontUnref(self->font.font); - PCF_CloseFont(self->font.font); - }else if(self->font.static_font){ - /* TODO: This is confusing. There should be only one - * of unref/free - * */ - PCF_StaticFontUnref(self->font.static_font); -// PCF_FreeStaticFont(self->font.static_font); - } -} - -void text_gauge_set_font(TextGauge *self, PCF_Font *font) -{ - text_gauge_dispose_font(self); - - self->font.font = font; - PCF_FontRef(self->font.font); - self->font.is_static = false; - - BASE_GAUGE(self)->dirty = true; -} - -void text_gauge_set_static_font(TextGauge *self, PCF_StaticFont *font) -{ - text_gauge_dispose_font(self); - - PCF_StaticFontRef(font); - self->font.static_font = font; - self->font.is_static = true; - - BASE_GAUGE(self)->dirty = true; -} - -void text_gauge_set_color(TextGauge *self, SDL_Color color, Uint8 which) -{ - if(which == TEXT_COLOR) - self->text_color = color; - else - self->bg_color = color; - - BASE_GAUGE(self)->dirty = true; -} - -/** - * @brief Ensure that the TextGauge can store at least - * @param size chars. - * - * TODO: Should be set_length or something that conveys the - * meaning of internal storage vs heigh/width - * - * @param self The TextGauge - * @param size the number of chars that need to be stored. - * The actual allocation will be size+1 to accomodate the - * trailing NULL byte. The internal size can be greater than - * @param size. - * - * @return True on success, false on failure. - */ -bool text_gauge_set_size(TextGauge *self, size_t size) -{ - - if(size+1 > self->asize){ - char *tmp; - tmp = realloc(self->value, (size+1) * sizeof(char)); - if(!tmp) return false; - self->asize = size+1; - self->value = tmp; - } - - if(size > self->state.achars){ - void *tmp; - tmp = realloc(self->state.chars, size * sizeof(PCF_StaticFontPatch)); - if(!tmp) return false; - self->state.chars = tmp; - self->state.achars = size; - } - - return true; -} - -/*TODO: Check if the static font can display the new value ?*/ -bool text_gauge_set_value(TextGauge *self, const char *value) -{ - int newlen; - /*TODO: This is going to be quite mem-intesive, use a pool or something - * and resort to allocation only when needing large pools*/ - newlen = strlen(value); - - if(!text_gauge_set_size(self, newlen)) - return false; - - strcpy(self->value, value); - self->len = newlen; - self->value[self->len] = '\0'; - - BASE_GAUGE(self)->dirty = true; - return true; -} - -/** - * @brief Sets the value of a TextGauge using a printf-like format. - * - * @param self a TextGauge - * @param size The maximum number of chars to print, excluding the NULL byte - * @param fmt A printf-like format string - * @param ... Arguments to the format - * - * @return True on success, false if all the chars couldn't be printed - */ -bool text_gauge_set_value_formatn(TextGauge *self, size_t size, const char *fmt, ...) -{ - va_list ap; - int rv; - - if(!text_gauge_set_size(self, size)) - return false; - - va_start(ap, fmt); - rv = vsnprintf(self->value, size+1, fmt, ap); - va_end(ap); - self->len = rv <= size ? rv : strlen(self->value); - BASE_GAUGE(self)->dirty = true; - return rv <= size; -} - -static inline void text_gauge_static_font_update_state(TextGauge *self, Uint32 dt) -{ - SDL_Rect farea; - SDL_Rect glyph, cursor; - PCF_StaticFont *sfont; - - if(!self->state.chars) - return; - - sfont = self->font.static_font; - - farea = (SDL_Rect){ - .x = 0, - .y = 0, - .w = base_gauge_w(BASE_GAUGE(self)), - .h = base_gauge_h(BASE_GAUGE(self)) - }; - - PCF_StaticFontGetSizeRequestRect(sfont, self->value, true, &cursor); - SDLExt_RectAlign(&cursor, &farea, self->alignment); - self->state.nchars = PCF_StaticFontPreWriteString(sfont, - self->len, self->value, - true, &cursor, - self->state.achars, self->state.chars - ); -} - -static inline void text_gauge_regular_font_update_state(TextGauge *self, Uint32 dt) -{ - if(!self->buffer){ - self->buffer = generic_layer_new(base_gauge_w(BASE_GAUGE(self)), base_gauge_h(BASE_GAUGE(self))); - } - - view_font_draw_text(self->buffer->canvas, NULL, - self->alignment, self->value, - self->font.font, - SDL_MapRGBA(self->buffer->canvas->format, - self->text_color.r, self->text_color.g, - self->text_color.b, self->text_color.a - ), - SDL_MapRGBA(self->buffer->canvas->format, - self->bg_color.r, self->bg_color.g, - self->bg_color.b, self->bg_color.a - ) - ); - generic_layer_update_texture(self->buffer); - printf("redrawn backbuffer\n"); -} - -static void text_gauge_update_state(TextGauge *self, Uint32 dt) -{ - if(!self->font.font) return; /*Wait until either font has been set*/ - - if(self->font.is_static){ - text_gauge_static_font_update_state(self, dt); - }else{ - text_gauge_regular_font_update_state(self, dt); - } -} - -static inline void text_gauge_static_font_render(TextGauge *self, Uint32 dt, - RenderContext *ctx) -{ - - base_gauge_fill(BASE_GAUGE(self), ctx, NULL, &self->bg_color, false); - if(self->outlined) - base_gauge_draw_outline(BASE_GAUGE(self), ctx, &SDL_WHITE, NULL); - - for(int i = 0; i < self->state.nchars; i++){ - base_gauge_draw_static_font_patch(BASE_GAUGE(self), - ctx, - self->font.static_font, - &self->state.chars[i] - ); - } -} - -static inline void text_gauge_regular_font_render(TextGauge *self, Uint32 dt, - RenderContext *ctx) -{ - - base_gauge_fill(BASE_GAUGE(self), ctx, NULL, &self->bg_color, false); - base_gauge_blit_layer(BASE_GAUGE(self), ctx, self->buffer, NULL, NULL); - - if(self->outlined) - base_gauge_draw_outline(BASE_GAUGE(self), ctx, &SDL_WHITE, NULL); -} - -static void text_gauge_render(TextGauge *self, Uint32 dt, RenderContext *ctx) -{ - if(!self->font.font) return; /*Wait until either font has been set*/ - - if(self->font.is_static){ - text_gauge_static_font_render(self, dt, ctx); - }else{ - text_gauge_regular_font_render(self, dt, ctx); - } -} diff --git a/text-gauge.h b/text-gauge.h deleted file mode 100644 index 7fdabdc..0000000 --- a/text-gauge.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef TEXT_GAUGE_H -#define TEXT_GAUGE_H -#include - -#include "base-gauge.h" -#include "SDL_pcf.h" -#include "generic-layer.h" -#include "view.h" - -#define TEXT_COLOR 0 -#define BACKGROUND_COLOR 1 - -typedef struct{ - PCF_StaticFontPatch *chars; - size_t achars; /*Allocated chars*/ - int nchars; -}TextGaugeState; - -typedef struct{ - BaseGauge super; - - PCFWrapFont font; - SDL_Color text_color; - SDL_Color bg_color; - uint8_t alignment; - bool outlined; - - char *value; - size_t asize; /*Allocated size*/ - size_t len; /*data size*/ - - TextGaugeState state; - /* Back buffer to use with regular fonts*/ - GenericLayer *buffer; -}TextGauge; - -TextGauge *text_gauge_new(const char *value, bool outlined, int w, int h); -TextGauge *text_gauge_init(TextGauge *self, const char *value, bool outlined, int w, int h); - -bool text_gauge_set_size(TextGauge *self, size_t size); -bool text_gauge_set_value(TextGauge *self, const char *value); -bool text_gauge_set_value_formatn(TextGauge *self, size_t size, const char *fmt, ...); -void text_gauge_set_color(TextGauge *self, SDL_Color color, Uint8 which); - -void text_gauge_set_font(TextGauge *self, PCF_Font *font); -void text_gauge_set_static_font(TextGauge *self, PCF_StaticFont *font); -#endif /* TEXT_GAUGE_H */ diff --git a/vertical-speed-indicator.c b/vertical-speed-indicator.c deleted file mode 100644 index 707fb4a..0000000 --- a/vertical-speed-indicator.c +++ /dev/null @@ -1,383 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include -#include -#include - -#include -#include "SDL_pcf.h" - -#include "SDL_surface.h" -#include "base-gauge.h" -#include "generic-layer.h" -#include "vertical-speed-indicator.h" -#include "resource-manager.h" -#include "sdl-colors.h" -#include "misc.h" -#include "view.h" - -static void vertical_speed_indicator_render(VerticalSpeedIndicator *self, Uint32 dt, RenderContext *ctx); -static void vertical_speed_indicator_update_state(VerticalSpeedIndicator *self, Uint32 dt); -static void *vertical_speed_indicator_dispose(VerticalSpeedIndicator *self); -static BaseGaugeOps vertical_speed_indicator_ops = { - .render = (RenderFunc)vertical_speed_indicator_render, - .update_state = (StateUpdateFunc)vertical_speed_indicator_update_state, - .dispose = (DisposeFunc)vertical_speed_indicator_dispose -}; - -static void vertical_speed_indicator_draw_background(VerticalSpeedIndicator *self, int width, int height, - uint8_t base_unit_px, uint8_t small_step_width, - uint8_t big_step_width, FontResource font); -static void vertical_speed_indicator_draw_cursor(VerticalSpeedIndicator *self); - -VerticalSpeedIndicator *vertical_speed_indicator_new(int width, int height, FontResource font) -{ - VerticalSpeedIndicator *self; - - self = calloc(1, sizeof(VerticalSpeedIndicator)); - if(self){ - if(!vertical_speed_indicator_init(self, width, height, font)){ - return base_gauge_free(BASE_GAUGE(self)); - } - } - return self; -} - -VerticalSpeedIndicator *vertical_speed_indicator_init(VerticalSpeedIndicator *self, int width, int height, FontResource font) -{ - bool rv; - - - self->font = resource_manager_get_static_font(font, &SDL_WHITE, 2, PCF_DIGITS, "+-"); - if(!self->font) - return NULL; - PCF_StaticFontRef(self->font); - - vertical_speed_indicator_draw_background( - self, width, height, - roundf(height*0.11f), roundf(width*0.24f), - roundf(width*0.33f), font - ); - vertical_speed_indicator_draw_cursor(self); - /*TODO: Check if drawing worked*/ - - generic_layer_build_texture(GENERIC_LAYER(&self->scale)); - generic_layer_build_texture(&self->cursor); - - /* TODO: Move me as first operation to ensure that Ops are always - * set when we return NULL so that base_gauge_dispose (called by - * base_gauge_free) can properly dispose any gauge-allocated resources*/ - base_gauge_init(BASE_GAUGE(self), - &vertical_speed_indicator_ops, - generic_layer_w(&self->cursor), - generic_layer_h(GENERIC_LAYER(&self->scale)) - ); - - return self; -} - -static void *vertical_speed_indicator_dispose(VerticalSpeedIndicator *self) -{ - vertical_strip_dispose(&self->scale); - generic_layer_dispose(&self->cursor); - if(self->font) - PCF_FreeStaticFont(self->font); - return self; -} - -bool vertical_speed_indicator_set_value(VerticalSpeedIndicator *self, float value, bool animated) -{ - return sfv_gauge_set_value(SFV_GAUGE(self), value, animated); -} - - -static void vertical_speed_indicator_update_state(VerticalSpeedIndicator *self, Uint32 dt) -{ - float y; - char number[VS_VALUE_MAX_LEN]; - int ivalue; - int len; -#if 0 /*Switch whether to align cursor text left/right*/ - uint8_t halign = HALIGN_RIGHT; -#else - uint8_t halign = HALIGN_LEFT; -#endif - -// printf("%s %p value: %f\n", __FUNCTION__, self, SFV_GAUGE(self)->value); - ivalue = round(SFV_GAUGE(self)->value); - len = snprintf(number, VS_VALUE_MAX_LEN, "% -d", ivalue); - vertical_strip_clip_value(&self->scale, &SFV_GAUGE(self)->value); - - y = vertical_strip_resolve_value(&self->scale, SFV_GAUGE(self)->value, true); - y = round(round(y) - generic_layer_h(&self->cursor)/2.0); - self->state.cloc = (SDL_Rect){ - 1, y, - generic_layer_w(&self->cursor), - generic_layer_h(&self->cursor) - }; - - /*This non-tight size request will include left and right "margins"*/ - PCF_StaticFontGetSizeRequestRect(self->font, number, true, &self->state.tloc); - SDLExt_RectAlign(&self->state.tloc, - &self->state.cloc, - halign | VALIGN_MIDDLE - ); - if(halign == HALIGN_LEFT){ - /* Pretend a sign (+/-) is always present to avoid the text - * "jumping" when the sign appears/disappears - */ - self->state.tloc.x += self->font->metrics.characterWidth; - }else{ - /*correct for the border width that is 1px*/ - self->state.tloc.x -= 1; - } - - SDL_Rect glyph, cursor; - cursor = self->state.tloc; - self->state.nchars = PCF_StaticFontPreWriteString(self->font, - len, number, - true, &cursor, - VS_VALUE_MAX_LEN-1, self->state.chars - ); -} - -static void vertical_speed_indicator_render(VerticalSpeedIndicator *self, Uint32 dt, RenderContext *ctx) -{ - base_gauge_blit_layer(BASE_GAUGE(self), ctx, - GENERIC_LAYER(&self->scale), NULL, - &(SDL_Rect){ - 0, 0, - generic_layer_w(GENERIC_LAYER(&self->scale)), - generic_layer_h(GENERIC_LAYER(&self->scale)) - } - ); - - base_gauge_blit_layer(BASE_GAUGE(self), ctx, - &self->cursor, NULL, &self->state.cloc - ); - - for(int i = 0; i < self->state.nchars; i++){ - base_gauge_draw_static_font_patch(BASE_GAUGE(self), - ctx, - self->font, - &self->state.chars[i] - ); - } -} - - -static void vertical_speed_indicator_draw_background(VerticalSpeedIndicator *self, int width, int height, - uint8_t base_unit_px, uint8_t small_step_width, - uint8_t big_step_width, FontResource font) -{ - int line1_y_start = 0; - int line2_y_start = 0; - - // assert height is odd ? - - - bool rv = generic_layer_init(GENERIC_LAYER(&self->scale), width, height); - if(!rv) - return; - - int mid_y = height/2; - line1_y_start = mid_y; - line2_y_start = mid_y; - - int aperture = 0.16 * height; - - int line1_y_end = mid_y - aperture/2; - int line1_x_end = (width-1); - int line1_x_start = 0; - - int line2_y_end = mid_y + aperture/2; - int line2_x_end = (width-1); - int line2_x_start = 0; - printf("%s: line1: %d,%d -> %d,%d\n", __FUNCTION__, 0, line1_y_start, line1_x_end, line1_y_end); - printf("%s: line2: %d,%d -> %d,%d\n", __FUNCTION__, 0, line2_y_start, line2_x_end, line2_y_end); - - int dy = abs(line1_y_end - line1_y_start); - - SDL_Surface *canvas = GENERIC_LAYER(&self->scale)->canvas; - view_draw_line(canvas, line1_x_start, line1_y_start, line1_x_end, line1_y_end, &(SDL_WHITE)); - view_draw_line(canvas, line2_x_start, line2_y_start, line2_x_end, line2_y_end, &(SDL_WHITE)); - - self->scale.ppv = base_unit_px/500.0; - self->scale.start = (500.0/base_unit_px) * (mid_y-(height-1)); - self->scale.end = (500.0/base_unit_px) * (mid_y - 0); - - - SDL_LockSurface(canvas); - Uint32 *pixels = canvas->pixels; - Uint32 white = SDL_UWHITE(canvas); - for(int x = 0; x < width; x++){ - pixels[0 * canvas->w + x] = white; - } - for(int x = 0; x < width; x++){ - pixels[(height-1) * canvas->w + x] = white; - } - - for(int y = 0; y < height; y++){ - pixels[y * canvas->w + 0] = white; - if(y > line1_y_end && y < line2_y_end) - continue; - - pixels[y * canvas->w + (width-1)] = white; - } - - int tick_drawn = 1; /* The midpoint is considered to be an undrawn tick (0)*/ - for(int y = mid_y-1; y >= 0; y--){ /*+1 skips the mid point tick*/ - if((y-mid_y) % base_unit_px == 0){ /* tick mark*/ - /* big tick mark, every two small ticks (500/1000) */ - uint8_t tick_width = (tick_drawn % 2 == 0) ? big_step_width : small_step_width; - for(int x = 1; x <= tick_width; x++){ - pixels[y * canvas->w + x] = white; - } - tick_drawn++; - } - } - - tick_drawn = 1; /* The midpoint is considered to be an undrawn tick (0)*/ - for(int y = mid_y+1; y < height; y++){ /*+1 skips the mid point tick*/ - if((y-mid_y) % base_unit_px == 0){ /* tick mark*/ - /* big tick mark, every two small ticks (500/1000) */ - uint8_t tick_width = (tick_drawn % 2 == 0) ? big_step_width : small_step_width; - for(int x = 1; x <= tick_width; x++){ - pixels[y * canvas->w + x] = white; - } - tick_drawn++; - } - } - - SDL_UnlockSurface(canvas); - int offset = 5; - PCF_Font *font_handle = resource_manager_get_font(font); - for(int i = -2000; i <= 2000; i += 500){ - if(i == 0) continue; /* skip zero */ - if(i % 1000) continue; /* only draw big ticks*/ - - int y = vertical_strip_resolve_value(&self->scale, i, true); - int val = abs(i / 1000); - PCF_FontWriteNumberAt(font_handle, - &val, TypeInt, 0, - white, false, canvas, - big_step_width + offset, y, RightToCol | CenterOnRow); - } -} - -static void vertical_speed_indicator_draw_cursor(VerticalSpeedIndicator *self) -{ - Uint32 c_h, c_w; - - assert(self->font != NULL); - - PCF_StaticFontGetSizeRequest(self->font, "9999", false, &c_w, &c_h); - c_w *= 1.2; - - int height = GENERIC_LAYER(&self->scale)->canvas->h; - - int mid_y = height/2; - int aperture = 0.16 * height; - aperture = MIN(aperture, c_h); -// printf("%s: height: %d mid_y: %d aperture: %d\n", __FUNCTION__, height, mid_y, aperture); - - int aperture_y_first = mid_y - aperture/2; - int aperture_y_last = mid_y + aperture/2; -// printf("%s: aperture_y_first: %d aperture_y_last: %d\n", __FUNCTION__, aperture_y_first, aperture_y_last); - - - int *frontiers = calloc(sizeof(int), aperture+1); /*+1 to account for the first row*/ - if(!frontiers){ - printf("%s: Failed to allocate frontiers\n", __FUNCTION__); - return; - } - SDL_Surface *canvas = GENERIC_LAYER(&self->scale)->canvas; - Uint32 white = SDL_UWHITE(canvas); - SDL_LockSurface(canvas); - Uint32 *pixels = canvas->pixels; - for(int y = aperture_y_first; y <= aperture_y_last; y++){ - for(int x = 0; x < canvas->w-1; x++){ - Uint32 pixel = pixels[(y*canvas->w) + x]; - if(pixel == white){ -// printf("Setting frontier[%d]: %d\n", y-aperture_y_first, x); - frontiers[y - aperture_y_first] = x; - } - } - } - - int ascent,descent; - int local_aperture; - for(int x = 1; x < canvas->w-1; x++){ - //for(ascent = mid_y; ascent >= aperture_y_first && pixels[(ascent*canvas->w) + x] != white; ascent--); - for(ascent = mid_y; ascent >= aperture_y_first; ascent--){ - Uint32 pixel = pixels[(ascent*canvas->w) + x]; - if(pixel == white){ - break; - } - } - for(descent = mid_y; descent <= aperture_y_last; descent++){ - Uint32 pixel = pixels[(descent*canvas->w) + x]; - if(pixel == white){ - break; - } - } - local_aperture = abs(ascent-mid_y) + (descent-mid_y); - if(local_aperture >= c_h){ - // printf("Local aperture: %d >= cursor height: %d\n", local_aperture, c_h); - // printf("Old cursor width: %d New cursor width: %d\n", c_w, c_w + x); - c_w += x; - break; - } - } - - - SDL_UnlockSurface(canvas); - - //printf("%s: cursor width: %d cursor height: %d\n", __FUNCTION__, c_w, c_h); - bool rv = generic_layer_init(&self->cursor, c_w, c_h); - if(!rv) - return; - canvas = self->cursor.canvas; - SDL_LockSurface(canvas); - pixels = canvas->pixels; - Uint32 black = SDL_UBLACK(canvas); - for(int y = 0; y < c_h && y < aperture; y++){ - for(int x = frontiers[y]+1; x < c_w; x++){ - pixels[(y*canvas->w) + x] = black; - } - } - -#if 1 /*Switch wheter to draw a border on the cursor*/ - /* border */ - white = SDL_UWHITE(canvas); - Uint32 amask = canvas->format->Amask; - Uint8 ashift = canvas->format->Ashift; - Uint8 alpha; - for(int y = 0; y < c_h && y < aperture; y++){ - for(int x = frontiers[y]+1; x < c_w; x++){ - Uint32 *pixel = pixels + (y*canvas->w) + x; - Uint32 *abel = y <= c_h/2 - ? pixels + ((y-1)*canvas->w) + x - : pixels + ((y+1)*canvas->w) + x; - if(*pixel != black) continue; - if(y == 0 || y == c_h-1 || x == c_w-1){ - *pixel = white; - } else { - alpha = (*abel & amask) >> ashift; - if(alpha != 0x00) continue; - - *pixel = white; - } - } - } -#endif - - SDL_UnlockSurface(canvas); - free(frontiers); -} diff --git a/vertical-speed-indicator.h b/vertical-speed-indicator.h deleted file mode 100644 index 0426b85..0000000 --- a/vertical-speed-indicator.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef VERTICAL_SPEED_INDICATOR_H -#define VERTICAL_SPEED_INDICATOR_H -#include "SDL_pcf.h" - -#include "resource-manager.h" -#include "sfv-gauge.h" -#include "generic-layer.h" -#include "vertical-strip.h" - -#define VS_VALUE_MAX_LEN 6 /*5 digits plus \0*/ - -typedef struct{ - SDL_Rect cloc; /*cursor location*/ - SDL_Rect tloc; /*text location*/ - - /* -1 because we don't need to render the \0*/ - PCF_StaticFontPatch chars[VS_VALUE_MAX_LEN-1]; - int nchars; -}VerticalSpeedIndicatorState; - -typedef struct{ - SfvGauge super; - - GenericLayer cursor; /*cursor background image*/ - - PCF_StaticFont *font; - - VerticalStrip scale; - - VerticalSpeedIndicatorState state; -}VerticalSpeedIndicator; - -VerticalSpeedIndicator *vertical_speed_indicator_new(int width, int height, FontResource font); -VerticalSpeedIndicator *vertical_speed_indicator_init(VerticalSpeedIndicator *self, int width, int height, FontResource font); - -bool vertical_speed_indicator_set_value(VerticalSpeedIndicator *self, float value, bool animated); -#endif /* VERTICAL_SPEED_INDICATOR_H */ diff --git a/vertical-strip.c b/vertical-strip.c deleted file mode 100644 index 9470a2d..0000000 --- a/vertical-strip.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include - -#include "generic-layer.h" -#include "vertical-strip.h" - -void vertical_strip_dispose(VerticalStrip *self) -{ - generic_layer_dispose(GENERIC_LAYER(self)); -} - -bool vertical_strip_has_value(VerticalStrip *self, float value) -{ - float min, max; - - min = (self->end > self->start) ? self->start : self->end; - max = (self->end < self->start) ? self->start : self->end; - - return value >= min && value <= max; -} - -/** - * Returns image pixel index (i.e y for vertical gauges, x for horizontal) - * from a given value. This function does a crude approximation that might fail - * to align with etch marks, if any. If there are any etch marks on the strip, - * derivative classes should handle them and call this function only to resolve - * values between marks - * - * @param value the value to look for - * @param reverse if true, assumes that 0 is a the bottom of the strip instead of - * at the top - * @return the pixel index in {@link #ruler} that maps to @value, or -1 if value can't - * be mapped (outside of the [{@link #start}, {@link #end}] range) - */ -float vertical_strip_resolve_value(VerticalStrip *self, float value, bool reverse) -{ - float rv; - /* To map [A, B] --> [a, b] - * - * use this formula : (val - A)*(b-a)/(B-A) + a - * - */ -/* first interval is start,end, second interval is 0,surface->h-1*/ - if(!reverse){ - rv = (value - self->start)*((generic_layer_h(GENERIC_LAYER(self))-1) - 0)/(self->end - self->start) + 0; -// printf("Forward: New resolve: mapping value %f from [%f %f] to [%d %d]: %f\n",value, self->start,self->end,0,self->ruler->h-1,rv); - }else{ - rv = (value - self->start)*(0 - (generic_layer_h(GENERIC_LAYER(self))-1))/(self->end - self->start) + (generic_layer_h(GENERIC_LAYER(self))-1); -// printf("Reverse: New resolve: mapping value %f from [%f %f] to [%d %d]: %f\n",value, self->start,self->end,self->ruler->h-1,0,rv); - } - return rv; -} - -void vertical_strip_clip_value(VerticalStrip *self, float *value) -{ - if(*value > self->end) - *value = self->end; - if(*value < self->start) - *value = self->start; -} diff --git a/vertical-strip.h b/vertical-strip.h deleted file mode 100644 index 222da4e..0000000 --- a/vertical-strip.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef VERTICAL_STRIP_H -#define VERTICAL_STRIP_H - -#include - -#include -#include - -#include "SDL_render.h" -#include "generic-layer.h" -/** - * Generic mapping between a range of values {@value #start}, {@value #start} - * and an image. - * - * TODO: Replace with GenericRuler - */ -typedef struct{ - GenericLayer super; - - float ppv; /* pixels per value*/ - float start, end; /*Range*/ -}VerticalStrip; - -#define VERTICAL_STRIP(self) ((VerticalStrip *)(self)) - -void vertical_strip_dispose(VerticalStrip *self); - -bool vertical_strip_has_value(VerticalStrip *self, float value); -float vertical_strip_resolve_value(VerticalStrip *self, float value, bool reverse); -void vertical_strip_clip_value(VerticalStrip *self, float *value); - -#endif /* VERTICAL_STRIP_H */ diff --git a/view.c b/view.c deleted file mode 100644 index cf8683f..0000000 --- a/view.c +++ /dev/null @@ -1,215 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include -#include -#include - -#include "SDL_pixels.h" -#include "SDL_surface.h" -#include "SDL_pcf.h" -#include "sdl-colors.h" -#include "view.h" -#include "misc.h" - -/** - * This file contains generic drawing code that is intended to make - * static draws directly on SDL_Surfaces. By static we mean that it - * should be used when we need to generate "textures" that then will - * be used without changes other than display coordinates on each frame. - * - * This is *NOT* intented to be used as per-frame drawing code. All the - * per-frame drawing code must be in BufferGauge where it can be switched - * from SDL_Blit to SDL_Renderer, and then to OpenGL. - */ - -/** - * Clear the area using the global color key (SDL_UCKEY) - * - */ -void view_clear(SDL_Surface *self, SDL_Rect *area) -{ - SDL_FillRect(self, area, SDL_UCKEY(self)); -} - -/** - * Draws a 1px line around the specified area. - * - * @param area The area to encompass with the outline, in self - * coordinates. This function does not bound-checking: Area MUST be cliped beforehand. - * If NULL, the whole view will be outlined. - * - */ -void view_draw_outline(SDL_Surface *self, SDL_Color *rgba, SDL_Rect *area) -{ - int x,y; - Uint32 *pixels; - Uint32 color; - SDL_Surface *canvas; - int startx,starty; - int endx, endy; - - canvas = self; - color = SDL_MapRGBA(self->format, rgba->r, rgba->g, rgba->b, rgba->a); - - /* Warning: end[xy] are not usable coordinates - * last usable coordinate: end[xy]-1 - */ - if(area){ - startx = area->x; - endx = area->x + area->w; - starty = area->y; - endy = area->y + area->h; - }else{ - startx = 0; - endx = self->w, - starty = 0; - endy = self->h; - } - -// printf("startx: %d endx: %d self->w: %d\n",startx,endx,self->w); -// printf("starty: %d endy: %d self->h: %d\n",starty,endy,self->h); - assert(startx >= 0 && endx <= self->w); - assert(starty >= 0 && endy <= self->h); - - SDL_LockSurface(canvas); - pixels = canvas->pixels; - - /*TODO: - * -For varying x (drawing top and bottom), do a memset on the range - * -For varying y (drawing left and right) set both left and right pixels - * while doing line y. - * */ - /*Top line*/ - y = starty; - for(x = startx; x < endx; x++){ - pixels[y * canvas->w + x] = color; - } - /*Bottom line*/ - y = endy - 1; - for(x = startx; x < endx; x++){ - pixels[y * canvas->w + x] = color; - } - /*Left side*/ - x = startx; - for(y = starty; y < endy; y++){ - pixels[y * canvas->w + x] = color; - } - /*Right side*/ - x = endx - 1; - for(y = starty; y < endy; y++){ - pixels[y * canvas->w + x] = color; - } - - SDL_UnlockSurface(canvas); -} - -void view_font_draw_text(SDL_Surface *destination, SDL_Rect *location, uint8_t alignment, const char *string, PCF_Font *font, Uint32 text_color, Uint32 bg_color) -{ - SDL_Rect aligned; - Uint32 ckey; - - location = location ? location : &(SDL_Rect){0, 0, destination->w, destination->h}; - - SDL_GetColorKey(destination, &ckey); - if(bg_color != ckey) - SDL_FillRect(destination, location, bg_color); - - PCF_FontGetSizeRequestRect(font, string, true, &aligned); - SDLExt_RectAlign(&aligned, location, alignment); - PCF_FontWrite(font, string, text_color, true, destination, &aligned); -} - - -/** - * Draw a "rubis" (the location where to current value - * aligns on the gauge. Akin to a centerline, but not - * necessarily located at then center) - * - * @param surface the surface to draw on - * @param y the line (relative to clip, if any, otherwise relative to surface) - * @param color color of the line - * @param pskip number of pixels to skip in the middle of the line. 0 for a full uninterrupted - * line - * @param clip optional clipping rectangle within surface. If not NULL, the function will consider - * only the portion of the surface encompassed by clip i.e: if surface is 640x480 and clip is - * {.x=40,.y=40,.w=20,.h=200} a call to view_draw_rubis with y = 10 will draw a line from - * {.x=50,.y=50} to {.x=50,.y=69} in surface. - */ -void view_draw_rubis(SDL_Surface *surface, int y, SDL_Color *color, int pskip, SDL_Rect *clip) -{ - Uint32 *pixels; - Uint32 col; - int startx, stopx; - int restartx, endx; - int liney, half; - - /* Warning: end[xy] are not usable coordinates - * last usable coordinate: end[xy]-1 - */ - if(clip){ - startx = clip->x; - endx = clip->x + clip->w; - liney = y + clip->y; - }else{ - startx = 0; - endx = surface->w; - liney = y; - } - - half = round(pskip/2.0); - stopx = startx + half; - restartx = endx - half; - - col = SDL_MapRGBA(surface->format, color->r, color->g, color->b, color->a); - SDL_LockSurface(surface); - pixels = surface->pixels; - for(int x = startx; x < endx; x++){ - if(!pskip || x < stopx || x >= restartx) - pixels[liney * surface->w + x] = col; - } - SDL_UnlockSurface(surface); -} - - -void view_draw_line(SDL_Surface *surface, int x0, int y0, int x1, int y1, SDL_Color *color) -{ - Uint32 *pixels; - Uint32 col; - int ybase; - - col = SDL_MapRGBA(surface->format, color->r, color->g, color->b, color->a); - SDL_LockSurface(surface); - pixels = surface->pixels; - - /* Bresenham's line algorithm */ - int dx = abs(x1 - x0); - int dy = abs(y1 - y0); - int sx = (x0 < x1) ? 1 : -1; - int sy = (y0 < y1) ? 1 : -1; - int err = dx - dy; - - ybase = y0; - for(;;) { - pixels[y0 * surface->w + x0] = col; - - if (x0 == x1 && y0 == y1) - break; - int err2 = 2 * err; - if (err2 > -dy) { - err -= dy; - x0 += sx; - } - if (err2 < dx) { - err += dx; - y0 += sy; - } - } - - SDL_UnlockSurface(surface); -} diff --git a/view.h b/view.h deleted file mode 100644 index 5501a10..0000000 --- a/view.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef VIEW_H -#define VIEW_H - -#include - -#include "SDL_pcf.h" - -typedef struct{ - union{ - PCF_Font *font; - PCF_StaticFont *static_font; - }; - bool is_static; -}PCFWrapFont; - -void view_clear(SDL_Surface *self, SDL_Rect *area); -void view_draw_outline(SDL_Surface *self, SDL_Color *rgba, SDL_Rect *area); -void view_draw_line(SDL_Surface *surface, int x0, int y0, int x1, int y1, SDL_Color *color); - -void view_font_draw_text(SDL_Surface *destination, SDL_Rect *location, uint8_t alignment, const char *string, PCF_Font *font, Uint32 text_color, Uint32 bg_color); - -void view_draw_rubis(SDL_Surface *surface, int y, SDL_Color *color, int pskip, SDL_Rect *clip); -#endif /* VIEW_H */ diff --git a/vruler-page-descriptor.c b/vruler-page-descriptor.c deleted file mode 100644 index 1f603d4..0000000 --- a/vruler-page-descriptor.c +++ /dev/null @@ -1,131 +0,0 @@ -#include -#include -#include - -#include "vruler-page-descriptor.h" -#include "misc.h" -#include "resource-manager.h" -#include "sizes.h" - - -/** - * @brief Initializes a VRulerPageDescriptor that is able to draw - * arbitrary pages of an infinite ruler ladder. - * - * This descriptor will draw a ruler having two levels of markings: big tick - * marks for big units (graduations) and small tick marks for small units - * (base units). - * - * @param self The VRulerPageDescriptor to initialize - * @param page_w The width of the page in pixels, that should match - * the LadderGauge size. - * @param page_h_min The minimum height of the page in pixels. That should be - * the height of the LadderGauge, but it will be rounded up to a multiple of a big unit height. - * @param unit_px_sz The *increment* in pixels from a base unit (small graduations) to the next one, - * e.g. if a base unit tick is at pixel y = 4 and unit_px_sz is 18, the next base unit tick will - * be at pixel y = 22. It is *not* the number of pixels *between* two graduations. The number of - * pixels between two graduations is unit_px_sz - the width of the tick mark, which is currently - * 1 pixel, thus unit_px_sz - 1. - * @param small_step_width The width in pixels of the small tick marks. - * @param big_step_width The width in pixels of the big tick marks. - * @param vstep The size of a big unit (graduation) in arbitrary units, e.g. 100. - * @param vsubstep The size of a small unit (base unit) in arbitrary units, e.g. 20. - * It must be a divisor of vstep, e.g. 100/20 = 5. - * @param direction The direction of the ladder, either BOTTOM_UP(ok) or TOP_DOWN(untested). - * @param func The function to use to initialize the LadderPage, e.g. vruler_ladder_page_init - * if you don't need anything more than drawing the ruler and etching the marks. - * - * @return The initialized VRulerPageDescriptor - */ - -VRulerPageDescriptor *vruler_page_descriptor_init(VRulerPageDescriptor *self, int page_w, - int page_h_min, uintf8_t unit_px_sz, - int small_step_width, int big_step_width, - float vstep, float vsubstep, - ScrollType direction, LPInitFunc func) -{ - int pattern_h; - - assert(fmodf(vstep, vsubstep) == 0); - - self->unit_px_sz = unit_px_sz; - self->big_step_width = big_step_width; - self->small_step_width = small_step_width; - - /* - * A small or base unit is vsubtep arbitrary units, such as 20, which will be - * represented by unit_px_sz. - * - * A big unit or graduation is vstep arbitrary units, such as 100. In this - * example a big unit is made of 5 small units. - */ - int small_units_per_big_unit = vstep/vsubstep; - - /* The final height will be a multiple of a "stitchable pattern" size. - * - * A "stitchable pattern" consists of half a big unit plus leading and - * trailing pixels so that if a pattern was stitched onto itself, leading - * pixels connected to trailing pixels, that would make 1 big unit. - * - * The size of a pattern is equivalent to one big unit. - */ - pattern_h = unit_px_sz * small_units_per_big_unit; - int page_h = round_up(page_h_min, pattern_h); - printf("Ruler ladder page height: %d, computed from: %d as a multiple of %d\n", page_h, page_h_min, pattern_h); - int npatterns = page_h/pattern_h; - - /*A page will represent page_size arbitrary unit values, e.g. 70. Those are not pixels*/ - float page_size = npatterns * vstep; - printf("Ruler ladder page size: %f, computed from: %d patterns of %d pixels\n", page_size, npatterns, pattern_h); - - - ladder_page_descriptor_init( - LADDER_PAGE_DESCRIPTOR(self), - page_w, page_h, - direction /*BOTTUM_UP*/, page_size, vstep /*100, big/graduation unit*/, vsubstep /*20, small/base unit*/, - func - ); - - /* We start the page pretending that we have already etched half a big unit. When the big unit - * is an odd number of pixels we draw the "bigger half" first and finish the page with the smaller - * half so that the pages ca be stiched together nicely. - * - * Therefore the first big tick mark is at the end of the page minus the half (or big half) the big - * unit pixel size. - */ - int n_steps; /*number of small steps to make a big step*/ - int step_px; - n_steps = LADDER_PAGE_DESCRIPTOR(self)->vstep/LADDER_PAGE_DESCRIPTOR(self)->vsubstep; - step_px = unit_px_sz* n_steps; - LADDER_PAGE_DESCRIPTOR(self)->fei = page_h - ceil(step_px/2.0); - printf("Ruler ladder page first etch mark index: %f\n", LADDER_PAGE_DESCRIPTOR(self)->fei); - - return self; -} - -/** - * @brief Draws the ruler and etches the markings on the page. - * - * This is where the drawing is done for a new page. Chain-up to it in - * your subclass (@see airspeed_ladder_page_init, altitude_ladder_page_init) - * - * @param self The LadderPage to initialize. - * @param location The location of the ruler, either LocationLeft or LocationRight. - * - * @return The initialized LadderPage with the ruler and markings drawn. - */ -LadderPage *vruler_ladder_page_init(LadderPage *self, LadderPageRulerLocation location) -{ - VRulerPageDescriptor *descriptor; - - descriptor = (VRulerPageDescriptor *)self->descriptor; - - ladder_page_init(self); - ladder_page_draw_ruler(self, descriptor->unit_px_sz, location, - descriptor->small_step_width, descriptor->big_step_width); - ladder_page_etch_markings(self, resource_manager_get_font(FONT_BIG), location == LocationRight ? HALIGN_RIGHT : HALIGN_LEFT, descriptor->big_step_width + 5); - - return self; -} - - diff --git a/vruler-page-descriptor.h b/vruler-page-descriptor.h deleted file mode 100644 index 5590c52..0000000 --- a/vruler-page-descriptor.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef VRULER_PAGE_DESCRIPTOR_H - -#include "ladder-page.h" - -typedef struct{ - LadderPageDescriptor super; - - uint8_t unit_px_sz; - uint8_t small_step_width; - uint8_t big_step_width; -}VRulerPageDescriptor; - -#define VRULER_PAGE_DESCRIPTOR(self) ((VRulerPageDescriptor*)(self)) - -VRulerPageDescriptor *vruler_page_descriptor_init(VRulerPageDescriptor *self, int page_w, - int page_h_min, uintf8_t unit_px_sz, - int small_step_width, int big_step_width, - float vstep, float vsubstep, - ScrollType direction, LPInitFunc func); - -LadderPage *vruler_ladder_page_init(LadderPage *self, LadderPageRulerLocation location); -#define VRULER_PAGE_DESCRIPTOR_H -#endif /* VRULER_PAGE_DESCRIPTOR_H */ diff --git a/widgets/base-widget.h b/widgets/base-widget.h deleted file mode 100644 index bcbe81e..0000000 --- a/widgets/base-widget.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef BASE_WIDGET_H -#define BASE_WIDGET_H -#include - -#include "base-gauge.h" - -#include "sdl-colors.h" - -typedef bool (*EventHandlerFunc)(void *self, SDL_KeyboardEvent *event); - -typedef struct{ - BaseGaugeOps super; - EventHandlerFunc handle_event; /*events from SDL (keyboard/mouse)*/ -}BaseWidgetOps; - -typedef struct _BaseWidget{ - BaseGauge super; - - bool has_focus; -}BaseWidget; - -/*events emitted by the widget: selection changed, etc.*/ -typedef void (*EventListenerFunc)(void *self, BaseWidget *sender); - -/** - * struct EventListener - Represents a listener - * @callback: The function that will be called when the event fires - * @target: The target of the event, i.e. the object to pass as self - * to the callback. This is *NOT* the widget that fired the event. - * - * Represents a listener as a "method", i.e. a function linked to an object. - * The function is assumed to take a pointer to its object as its first - * parameter. @see EventListenerFunc. - */ -typedef struct{ - EventListenerFunc callback; - void *target; -}EventListener; - -#define BASE_WIDGET(self) ((BaseWidget*)(self)) -#define BASE_WIDGET_OPS(self) ((BaseWidgetOps*)(self)) - -static inline BaseWidget *base_widget_init(BaseWidget *self, BaseWidgetOps *ops, - int w, int h) -{ - - return (BaseWidget *)base_gauge_init(BASE_GAUGE(self), - BASE_GAUGE_OPS(ops), - w, h - ); -} - -/*return false when the widget wants to give up focus*/ -static inline bool base_widget_handle_event(BaseWidget *self, - SDL_KeyboardEvent *event) -{ - if(BASE_WIDGET_OPS(BASE_GAUGE(self)->ops)->handle_event) - return BASE_WIDGET_OPS(BASE_GAUGE(self)->ops)->handle_event(self, event); - return false; -} - -static inline void base_widget_draw_outline(BaseWidget *self, RenderContext *ctx) -{ - base_gauge_draw_outline(BASE_GAUGE(self), - ctx, - self->has_focus ? &SDL_GREEN : &SDL_WHITE, - NULL - ); -} -#endif /* BASE_WIDGET_H */ diff --git a/widgets/button.c b/widgets/button.c deleted file mode 100644 index 611f8e5..0000000 --- a/widgets/button.c +++ /dev/null @@ -1,148 +0,0 @@ -#include -#include - -#include "SDL_pcf.h" -#include "base-gauge.h" -#include "button.h" -#include "misc.h" -#include "resource-manager.h" -#include "sdl-colors.h" -#include "text-gauge.h" - -static void button_render(Button *self, Uint32 dt, RenderContext *ctx); -static bool button_handle_event(Button *self, SDL_KeyboardEvent *event); - -static BaseWidgetOps button_ops = { - .super.update_state = (StateUpdateFunc)NULL, - .super.render = (RenderFunc)button_render, - .super.dispose = (DisposeFunc)NULL, - .handle_event = (EventHandlerFunc)button_handle_event -}; - - -Button *button_new(const char *caption, FontResource font_id, SDL_Color text_color, SDL_Color bg_color, int w, int h) -{ - Button *self; - - self = calloc(1, sizeof(Button)); - if(self){ - if(!button_init(self, caption, font_id, text_color, bg_color, w, h)){ - return base_gauge_free(BASE_GAUGE(self)); - } - } - return self; -} - -Button *button_init(Button *self, const char *caption, FontResource font_id, SDL_Color text_color, SDL_Color bg_color, int w, int h) -{ - base_widget_init(BASE_WIDGET(self), - &button_ops, - w, h - ); - - self->font_id = font_id; - - /*TODO: Have a text_gauge_get_size_request ?*/ - PCF_StaticFont *sfont = resource_manager_get_static_font( - self->font_id, &text_color, - 1, caption - ); - if(!sfont) return NULL; - - SDL_Rect text_rect; - PCF_StaticFontGetSizeRequestRect(sfont, caption, true, &text_rect); - -#if 0 - if(text_rect.w > w - 2*self->border_width - 1 || text_rect.h > h - 2*self->border_width - 1){ - /*TODO: Have TextGauge render write an ellipsis(...) as a single char - * where there is not enough space to write the full text*/ - /*TODO: Log the failure ?*/ - printf("Button: Cannot init widget with a size of (w:%d,h:%d) while the minimum computed size is (w:%d,h:%d)\n", - w, h, - text_rect.w + 2*self->border_width + 1, - text_rect.h + 2*self->border_width + 1 - ); - return NULL; - } -#endif - SDLExt_RectCenter(&text_rect, &(SDL_Rect){.w = w, .h = h }); - - self->text = text_gauge_new(NULL, false, text_rect.w, text_rect.h); - text_gauge_set_color(self->text, text_color, TEXT_COLOR); - text_gauge_set_color(self->text, bg_color, BACKGROUND_COLOR); - - self->text->alignment = HALIGN_CENTER | VALIGN_MIDDLE; - button_set_caption(self, caption); - - base_gauge_add_child(BASE_GAUGE(self), BASE_GAUGE(self->text), text_rect.x , text_rect.y); - - return self; -} - -bool button_set_caption(Button *self, const char *caption) -{ - bool rv; - - PCF_StaticFont *sfont = resource_manager_get_static_font( - self->font_id, &self->text->text_color, - 1, caption - ); - if(!sfont) - return false; - - rv = text_gauge_set_value(self->text, caption); - if(!rv) - return rv; - - text_gauge_set_static_font(self->text, sfont); - - return true; -} - -bool button_set_color(Button *self, SDL_Color color, Uint8 which) -{ - if(which == TEXT_COLOR){ - PCF_StaticFont *sfont = resource_manager_get_static_font( - self->font_id, &color, - 1, self->text->value - ); - if(!sfont) - return false; - - text_gauge_set_static_font(self->text, sfont); - }else if(which == BACKGROUND_COLOR){ - text_gauge_set_color(self->text, color, BACKGROUND_COLOR); - } - BASE_GAUGE(self)->dirty = true; - return true; -} - -static void button_render(Button *self, Uint32 dt, RenderContext *ctx) -{ - base_gauge_fill(BASE_GAUGE(self), ctx, NULL, &(self->text->bg_color), false); - base_widget_draw_outline(BASE_WIDGET(self), ctx); -} - - - -/*Should be button_handle_sdl_event */ -static bool button_handle_event(Button *self, SDL_KeyboardEvent *event) -{ - if(event->state != SDL_PRESSED) return true; - - switch(event->keysym.sym){ - case SDLK_RETURN: - if(self->validated.callback) - self->validated.callback(self->validated.target, BASE_WIDGET(self)); - else - return false; - break; - case SDLK_UP: /*Fallthrough*/ - case SDLK_DOWN: /*Give back focus*/ - return false; - break; - } - return true; -} - - diff --git a/widgets/button.h b/widgets/button.h deleted file mode 100644 index 79dfe1e..0000000 --- a/widgets/button.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef BUTTON_H -#define BUTTON_H - -#include "text-gauge.h" -#include "base-widget.h" -#include "resource-manager.h" - -typedef struct { - BaseWidget super; - - FontResource font_id; - TextGauge *text; - - EventListener validated; -}Button; - -#define BUTTON(self) ((Button *)(self)) - -Button *button_new(const char *caption, FontResource font_id, SDL_Color text_color, SDL_Color bg_color, int w, int h); -Button *button_init(Button *self, const char *caption, FontResource font_id, SDL_Color text_color, SDL_Color bg_color, int w, int h); - -bool button_set_caption(Button *self, const char *caption); -bool button_set_color(Button *self, SDL_Color color, Uint8 which); -#endif /* BUTTON_H */ diff --git a/widgets/inset-softkey-model.c b/widgets/inset-softkey-model.c deleted file mode 100644 index 0f535de..0000000 --- a/widgets/inset-softkey-model.c +++ /dev/null @@ -1,98 +0,0 @@ -#include -#include - -#include "inset-softkey-model.h" -#include "softkey-model.h" -#include "softkey.h" - -static SoftkeyDetails inset_softkeys[] = { - { - .caption = "OFF", - }, - { - .caption = "DCLTR", - }, - { - .caption = "WXLGND", - }, - { - .caption = "TRAFFIC", - }, - { - .caption = "TOPO", - }, - { - .caption = "TERRAIN", - }, - { - .caption = "STRMSCP", - }, - { - .caption = "NEXRAD", - }, - { - .caption = "XM LTNG", - }, - { - .caption = "METAR", - }, - { - .caption = "BACK", - .type = SOFTKEY_TYPE_BACK - }, - { - .caption = "ALERTS", - }, -}; - - -static InsetSoftkeyModel *inset_softkey_model_new(); -static InsetSoftkeyModel *inset_softkey_model_init(InsetSoftkeyModel *self); -static SoftkeyDetails *inset_softkey_model_get_details_at(SoftkeyModel *self, uint_fast8_t index); -static SoftkeyModelOps inset_softkey_model_ops = { -// .dispose = (DisposeFunc)airport_list_model_dispose - .get_details_at = inset_softkey_model_get_details_at -}; - -static InsetSoftkeyModel *instance = NULL; - - -InsetSoftkeyModel *inset_softkey_model_get_instance(void) -{ - if(!instance){ - instance = inset_softkey_model_new(); - } - return instance; -} - -static InsetSoftkeyModel *inset_softkey_model_new() -{ - InsetSoftkeyModel *self; - - self = calloc(1, sizeof(InsetSoftkeyModel)); - if(self){ - if(!inset_softkey_model_init(self)){ - return NULL; - } - } - return self; -} - -static InsetSoftkeyModel *inset_softkey_model_init(InsetSoftkeyModel *self) -{ - softkey_model_init(SOFTKEY_MODEL(self), &inset_softkey_model_ops); - - return self; -} - -static SoftkeyDetails *inset_softkey_model_get_details_at(SoftkeyModel *self, uint_fast8_t index) -{ - return &(inset_softkeys[index]); -} - -static void inset_softkey_model_inset_button_pressed(SoftkeyModel *self, Softkey *button) -{ - void *softkeybar = BASE_GAUGE(button)->parent; - - //softkey_bar_set_model(pdf_inset_softkey_model_get_instance()); -} diff --git a/widgets/inset-softkey-model.h b/widgets/inset-softkey-model.h deleted file mode 100644 index cfe12c2..0000000 --- a/widgets/inset-softkey-model.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef INSET_SOFTKEY_MODEL_H -#define INSET_SOFTKEY_MODEL_H - -#include "softkey-model.h" - -typedef struct{ - SoftkeyModel super; -}InsetSoftkeyModel; - - -InsetSoftkeyModel *inset_softkey_model_get_instance(void); -#endif /* INSET_SOFTKEY_MODEL_H */ diff --git a/widgets/list-box.c b/widgets/list-box.c deleted file mode 100644 index b8903e2..0000000 --- a/widgets/list-box.c +++ /dev/null @@ -1,304 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include -#include - -#include "SDL_keycode.h" -#include "SDL_pcf.h" -#include "base-gauge.h" -#include "list-model.h" -#include "resource-manager.h" -#include "sdl-colors.h" - -#include "misc.h" -#include "text-box.h" -#include "list-box.h" - - -static void list_box_update(ListBox *self, Uint32 dt); -static void list_box_render(ListBox *self, Uint32 dt, RenderContext *ctx); -static ListBox *list_box_dispose(ListBox *self); -static bool list_box_handle_event(ListBox *self, SDL_KeyboardEvent *event); -static BaseWidgetOps list_box_ops = { - .super.render = (RenderFunc)list_box_render, - .super.update_state = (StateUpdateFunc)list_box_update, - .super.dispose = (DisposeFunc)list_box_dispose, - .handle_event = (EventHandlerFunc)list_box_handle_event, -}; - - -static inline void list_box_fire_selection_changed(ListBox *self); - -/** - * Takes ownership of the model (i.e. will free it) - * - */ -ListBox *list_box_new(FontResource font_id, int width, int height) -{ - ListBox *self; - - self = calloc(1, sizeof(ListBox)); - if(self){ - if(!list_box_init(self, font_id, width, height)) - return base_gauge_free(BASE_GAUGE(self)); - } - return self; -} - -ListBox *list_box_init(ListBox *self, FontResource font_id, int width, int height) -{ - base_widget_init(BASE_WIDGET(self), - &list_box_ops, - width, height - ); - - - font_id = font_id; - PCF_Font *font = resource_manager_get_font(font_id); - size_t nhchars = ceilf((BASE_GAUGE(self)->frame.w*1.0)/PCF_FontCharWidth(font)); - size_t nvchars = ceilf((BASE_GAUGE(self)->frame.h*1.0)/PCF_FontCharHeight(font)); - - /* We need one more when scrolled horizontally and one more when scrolled - * vertically. - * A 4-chars wide/tall listbox can display - * 1 char partly, 3 chars and 1 more char partly with - * first width + last width = 1 full char width*/ - self->state.apatches = (nhchars+1) * (nvchars+1); - self->state.patches = malloc(sizeof(PCF_StaticFontPatch) - * self->state.apatches - ); - printf("allocated %zu patches\n", self->state.apatches); - - self->sfont = resource_manager_get_static_font(font_id, - &SDL_WHITE, - 1, - ASCII_PRINTABLE - ); - if(!self->sfont) - return NULL; - PCF_StaticFontCreateTexture(self->sfont); - - - BASE_GAUGE(self)->dirty = true; - - return self; -} - -static ListBox *list_box_dispose(ListBox *self) -{ - if(self->sfont) - PCF_StaticFontUnref(self->sfont); - if(self->state.patches) - free(self->state.patches); - if(self->model) - list_model_free(self->model); - return self; -} - -void list_box_set_model(ListBox *self, ListModel *model) -{ - self->model = model; - model->listbox = self; - list_box_model_changed(self); -} - -void list_box_model_changed(ListBox *self) -{ - self->text_size.h = self->model->nrows * PCF_StaticFontCharHeight(self->sfont); - self->text_size.w = self->model->maxlen * PCF_StaticFontCharWidth(self->sfont); - - self->selected_row = 0; - self->state.selected_h = 0; - self->state.selected_y = 0; - BASE_GAUGE(self)->dirty = true; - - list_box_fire_selection_changed(self); -} - -bool list_box_horizontal_scroll(ListBox *self, int_fast8_t direction) -{ - if(direction < 0 && self->state.offset.x <= 0) - return false; - if(direction > 0 && self->state.offset.x+BASE_GAUGE(self)->frame.w >= self->text_size.w) - return false; - self->state.offset.x += direction; - - BASE_GAUGE(self)->dirty = true; - return true; -} - -bool list_box_vertical_scroll(ListBox *self, int_fast8_t direction) -{ - size_t old_selected; - - old_selected = self->selected_row; - if(direction > 0){ - if(self->selected_row < self->model->nrows-1) - self->selected_row++; - }else if(direction < 0){ - if(self->selected_row > 0) - self->selected_row--; - } - if(self->selected_row != old_selected){ - list_box_fire_selection_changed(self); - BASE_GAUGE(self)->dirty = true; - } - - return BASE_GAUGE(self)->dirty; -} - - -static void list_box_update(ListBox *self, Uint32 dt) -{ - ListBoxState *state; - SDL_Rect glyph; - size_t current_height; - - state = &(self->state); - if(self->model->nrows == 0){ - state->npatches = 0; - return; - } - - int chary = self->selected_row * PCF_StaticFontCharHeight(self->sfont); - /*no need to -1 *both* for cmp*/ - int outy = chary + PCF_StaticFontCharHeight(self->sfont); /*first pixel out of glyph*/ - if(outy > state->offset.y + BASE_GAUGE(self)->frame.h){ - state->offset.y = (outy-1) - (BASE_GAUGE(self)->frame.h-1); - }else if(chary < state->offset.y){ - state->offset.y = chary; - } - - size_t ibegin_v, iend_v; /*string indices*/ - ibegin_v = state->offset.y / PCF_StaticFontCharHeight(self->sfont); - Uint32 endy = state->offset.y + (MIN(BASE_GAUGE(self)->frame.h, self->text_size.h)-1); - iend_v = ceilf(endy*1.0f/PCF_StaticFontCharHeight(self->sfont)); - iend_v = MIN(iend_v, self->model->nrows); - - state->npatches = 0; /*TODO compute*/ - current_height = 0; - for(int y = ibegin_v; y < iend_v; y++){ - int yremaining = BASE_GAUGE(self)->frame.h - current_height - 1; - int line_height = MIN( - PCF_StaticFontCharHeight(self->sfont), - yremaining - ); - SDL_Rect tarea = { - 0,0, - BASE_GAUGE(self)->frame.w, - BASE_GAUGE(self)->frame.h - }; - tarea.y += current_height; - tarea.h = (BASE_GAUGE(self)->frame.h-1) - tarea.y + 1; - - int lyoffset = 0; - if(y == ibegin_v){ - lyoffset = state->offset.y % PCF_StaticFontCharHeight(self->sfont); - } - - size_t n_line_patches; - n_line_patches = PCF_StaticFontPreWriteStringOffset( - self->sfont, - self->model->row_lenghts[y], - self->model->rows[y].label, - false, - &tarea, - state->offset.x * -1, lyoffset * -1, - state->apatches - state->npatches, - state->patches + state->npatches - ); -#if 0 - printf("Line %d patches:\n", y); - for(int i = state->npatches; i < state->npatches + n_line_patches; i++){ - printf("\tPatch[%d]: src(x:%d y:%d w:%d h:%d) dst:(x:%d y:%d)\n", i, - state->patches[i].src.x, state->patches[i].src.y, - state->patches[i].src.w, state->patches[i].src.h, - state->patches[i].dst.x, - state->patches[i].dst.y - ); - } -#endif - state->npatches += n_line_patches; - if(n_line_patches){ - line_height = state->patches[state->npatches-1].src.h; - } - if(y == self->selected_row && n_line_patches){ - state->selected_y = state->patches[state->npatches-1].dst.y; - state->selected_h = line_height; - } - current_height += line_height; - } - BASE_GAUGE(self)->dirty = false; -} - -static void list_box_render(ListBox *self, Uint32 dt, RenderContext *ctx) -{ - SDL_Color cursor_background; - - cursor_background = (SDL_Color){112,128,144, SDL_ALPHA_OPAQUE}; - if(BASE_WIDGET(self)->has_focus) - cursor_background = (SDL_Color){255,0,0,SDL_ALPHA_OPAQUE}; - - - if(self->state.selected_h){ - base_gauge_fill(BASE_GAUGE(self), ctx, &(SDL_Rect){ - 0, self->state.selected_y, - BASE_GAUGE(self)->frame.w, - self->state.selected_h - }, - &cursor_background, false - ); - - } - - for(int i = 0; i < self->state.npatches; i++){ - if(self->state.patches[i].src.x < 0) continue; - - base_gauge_draw_static_font_rect_patch(BASE_GAUGE(self), ctx, - self->sfont, - &self->state.patches[i] - ); - } - - base_widget_draw_outline(BASE_WIDGET(self), ctx); -} - -static bool list_box_handle_event(ListBox *self, SDL_KeyboardEvent *event) -{ - if(event->state != SDL_PRESSED) return true; - - switch(event->keysym.sym){ - case SDLK_UP: - list_box_vertical_scroll(self, -1); - break; - case SDLK_DOWN: - list_box_vertical_scroll(self, 1); - break; - case SDLK_LEFT: - list_box_horizontal_scroll(self, -1); - break; - case SDLK_RIGHT: - list_box_horizontal_scroll(self, 1); - break; - case SDLK_RETURN: - return false; - break; - } - return true; -} - -static inline void list_box_fire_selection_changed(ListBox *self) -{ - if(self->selection_changed.callback){ - self->selection_changed.callback( - self->selection_changed.target, - BASE_WIDGET(self) - ); - } -} diff --git a/widgets/list-box.h b/widgets/list-box.h deleted file mode 100644 index 5f3be0f..0000000 --- a/widgets/list-box.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef LIST_BOX_H -#define LIST_BOX_H -#include "SDL_pcf.h" - -#include "base-widget.h" -#include "resource-manager.h" -#include "list-model.h" - -#ifndef SDLEXT_UPOINT -#define SDLEXT_UPOINT -typedef struct{ - Uint32 x; - Uint32 y; -}SDLExt_UPoint; -#endif - -typedef struct{ - PCF_StaticFontPatch *patches; - size_t apatches; - size_t npatches; - Uint32 selected_y; - Uint32 selected_h; - - SDLExt_UPoint offset; /*offset in the virtual rectangle*/ -}ListBoxState; - -typedef struct _ListBox{ - BaseWidget super; - - uint_fast8_t font_size; /*RFU*/ - PCF_StaticFont *sfont; - - ListModel *model; - size_t selected_row; - - SDL_Rect text_size; /*Virtual rectangle with the whole text*/ - - ListBoxState state; - - EventListener selection_changed; -}ListBox; - - -ListBox *list_box_new(FontResource font_id, int width, int height); -ListBox *list_box_init(ListBox *self, FontResource font_id, int width, int height); - -void list_box_set_model(ListBox *self, ListModel *model); -void list_box_model_changed(ListBox *self); - -bool list_box_vertical_scroll(ListBox *self, int_fast8_t direction); -bool list_box_horizontal_scroll(ListBox *self, int_fast8_t direction); - -static inline ListModelRow *list_box_get_selected(ListBox *self) -{ - if(!self->model || self->selected_row >= self->model->nrows) - return NULL; - - return &self->model->rows[self->selected_row]; -} - -static inline void list_box_set_selection_changed_listener(ListBox *self, EventListenerFunc callback, void *target) -{ - self->selection_changed.callback = callback; - self->selection_changed.target = target; -} - -#endif /* LIST_BOX_H */ diff --git a/widgets/list-model.c b/widgets/list-model.c deleted file mode 100644 index 409c248..0000000 --- a/widgets/list-model.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include - -#include "list-model.h" - -/** - * @brief Allocate @param arows - * - */ -ListModel *list_model_init(ListModel *self, ListModelOps *ops, int arows) -{ - self->ops = ops; - - self->rows = malloc(sizeof(ListModelRow)*arows); - if(!self->rows) - return NULL; - - self->row_lenghts = malloc(sizeof(size_t)*arows); - if(!self->row_lenghts) - return NULL; /*TODO: leaks self->rows*/ - - self->arows = arows; - - return self; -} - -ListModel *list_model_dispose(ListModel *self) -{ - if(self->rows) - free(self->rows); - if(self->arows) - free(self->row_lenghts); - /*TODO: Use ops->dispose ?*/ - return self; -} diff --git a/widgets/list-model.h b/widgets/list-model.h deleted file mode 100644 index 026bce8..0000000 --- a/widgets/list-model.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef LIST_MODEL_H -#define LIST_MODEL_H -#include - -typedef void* (*DisposeFunc)(void *self); - -typedef struct _ListBox ListBox; - -typedef struct{ - DisposeFunc dispose; -}ListModelOps; - -typedef struct{ - char *label; - void *key; -}ListModelRow; - -typedef struct{ - ListModelOps *ops; - - ListBox *listbox; - /** - * This is the standard interface used by ListBox - * ListModel derivatives should fill those with - * appropriate data. - * */ - ListModelRow *rows; - size_t nrows; - size_t arows; - size_t *row_lenghts; - size_t maxlen; /*strlen of the largest row*/ -}ListModel; - -#define LIST_MODEL(self) ((ListModel *)(self)) -#define LIST_MODEL_OPS(self) ((ListModelOps *)(self)) - -ListModel *list_model_init(ListModel *self, ListModelOps *ops, int arows); -ListModel *list_model_dispose(ListModel *self); - -static inline ListModel *list_model_free(ListModel *self) -{ - if(self->ops->dispose) - self->ops->dispose(self); - free(self); - return NULL; -} - -#endif /* LIST_MODEL_H */ diff --git a/widgets/pfd-toplevel-softkey-model.c b/widgets/pfd-toplevel-softkey-model.c deleted file mode 100644 index 5112a39..0000000 --- a/widgets/pfd-toplevel-softkey-model.c +++ /dev/null @@ -1,103 +0,0 @@ -#include -#include - -#include "inset-softkey-model.h" -#include "pfd-toplevel-softkey-model.h" -#include "softkey-model.h" -#include "softkey.h" - -static SoftkeyDetails pfd_toplevel_softkeys[] = { - { - .caption = "INSET", - .type = SOFTKEY_TYPE_SEGUE, - .action.next = NULL - }, - { - .caption = "PFD", - }, - { - .caption = "OBS", - }, - { - .caption = "CDI", - }, - { - .caption = "DME", - }, - { - .caption = "XPDR", - }, - { - .caption = "IDENT", - }, - { - .caption = "TMR/REF", - }, - { - .caption = "NRST", - }, - { - .caption = "ALERTS", - }, -}; - - -static PfdToplevelSoftkeyModel *pfd_toplevel_softkey_model_new(); -static PfdToplevelSoftkeyModel *pfd_toplevel_softkey_model_init(PfdToplevelSoftkeyModel *self); -static SoftkeyDetails *pfd_toplevel_softkey_model_get_details_at(SoftkeyModel *self, uint_fast8_t index); -static SoftkeyModelOps pfd_toplevel_softkey_model_ops = { -// .dispose = (DisposeFunc)airport_list_model_dispose - .get_details_at = pfd_toplevel_softkey_model_get_details_at -}; - - -static PfdToplevelSoftkeyModel *instance = NULL; - - -PfdToplevelSoftkeyModel *pfd_toplevel_softkey_model_get_instance(void) -{ - if(!instance){ - instance = pfd_toplevel_softkey_model_new(); - } - return instance; -} - -static PfdToplevelSoftkeyModel *pfd_toplevel_softkey_model_new() -{ - PfdToplevelSoftkeyModel *self; - - self = calloc(1, sizeof(PfdToplevelSoftkeyModel)); - if(self){ - if(!pfd_toplevel_softkey_model_init(self)){ - return NULL; - } - } - return self; -} - -static PfdToplevelSoftkeyModel *pfd_toplevel_softkey_model_init(PfdToplevelSoftkeyModel *self) -{ - softkey_model_init(SOFTKEY_MODEL(self), &pfd_toplevel_softkey_model_ops); - pfd_toplevel_softkeys[0].action.next = SOFTKEY_MODEL(inset_softkey_model_get_instance()); - - return self; -} - -static SoftkeyDetails *pfd_toplevel_softkey_model_get_details_at(SoftkeyModel *self, uint_fast8_t index) -{ - if(index == 0 || index == 2) return NULL; - - if(index == 1) return &(pfd_toplevel_softkeys[0]); - - /* Plus one to skip the first storage array element which is button index 1 (second one) - * minus 3 to "rebase" the index: All buttons are stored in order starting button 3 (4th one) - * */ - return &(pfd_toplevel_softkeys[index+1-3]); -} - -static void pfd_toplevel_softkey_model_inset_button_pressed(SoftkeyModel *self, Softkey *button) -{ - void *softkeybar = BASE_GAUGE(button)->parent; - - //softkey_bar_set_model(pdf_inset_softkey_model_get_instance()); -} diff --git a/widgets/pfd-toplevel-softkey-model.h b/widgets/pfd-toplevel-softkey-model.h deleted file mode 100644 index 127af1b..0000000 --- a/widgets/pfd-toplevel-softkey-model.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef PFD_TOPLEVEL_SOFTKEY_MODEL_H -#define PFD_TOPLEVEL_SOFTKEY_MODEL_H - -#include "softkey-model.h" - -typedef struct{ - SoftkeyModel super; -}PfdToplevelSoftkeyModel; - - -PfdToplevelSoftkeyModel *pfd_toplevel_softkey_model_get_instance(void); -#endif /* PFD_TOPLEVEL_SOFTKEY_MODEL_H */ diff --git a/widgets/softkey-bar.c b/widgets/softkey-bar.c deleted file mode 100644 index 5d05ad9..0000000 --- a/widgets/softkey-bar.c +++ /dev/null @@ -1,166 +0,0 @@ -#include "softkey-bar.h" -#include "SDL_events.h" -#include "SDL_keycode.h" -#include "SDL_pcf.h" -#include "base-gauge.h" -#include "button.h" -#include "softkey.h" -#include "misc.h" -#include "resource-manager.h" -#include "sdl-colors.h" -#include "softkey-model.h" - -#define SOFTKEY_BAR_W 640 -#define SOFTKEY_BAR_H 16 -#define SOFTKEY_BUTTON_W 53 -#define SOFTKEY_BUTTON_H 16 - - -static intf8_t softkey_bar_key_to_button_index(SDL_KeyboardEvent *event); - -static void softkey_bar_render(SoftkeyBar *self, Uint32 dt, RenderContext *ctx); -static bool softkey_bar_handle_event(SoftkeyBar *self, SDL_KeyboardEvent *event); - -static BaseWidgetOps softkey_bar_ops = { - .super.update_state = (StateUpdateFunc)NULL, - .super.render = (RenderFunc)softkey_bar_render, - .super.dispose = (DisposeFunc)NULL, - .handle_event = (EventHandlerFunc)softkey_bar_handle_event -}; - - -SoftkeyBar *softkey_bar_new(FontResource font_id, SoftkeyModel *model) -{ - SoftkeyBar *self; - - self = calloc(1, sizeof(SoftkeyBar)); - if(self){ - if(!softkey_bar_init(self, model, font_id, SOFTKEY_BAR_W, SOFTKEY_BAR_H)){ - return base_gauge_free(BASE_GAUGE(self)); - } - } - return self; -} - -SoftkeyBar *softkey_bar_init(SoftkeyBar *self, SoftkeyModel *model, FontResource font_id, int w, int h) -{ - base_widget_init(BASE_WIDGET(self), - &softkey_bar_ops, - w, h - ); - - self->model = model; - - /* The following is a trick to pre-load needed glyph - * TODO: Have a self-configuration mechanism for the ResourceManager: - * save to a file what was needed in the previous run and merge as one - * big font. - * */ - PCF_StaticFont *sfont = resource_manager_get_static_font( - font_id, &SDL_WHITE, - 1, PCF_UPPER_CASE - ); - if(!sfont) return NULL; - - for(int i = 0, x = 2; i < N_SOFTKEYS; i++, x += SOFTKEY_BUTTON_W){ - SoftkeyDetails *details = self->model - ? softkey_model_get_details_at(self->model, i) - : NULL; - softkey_init(&(self->buttons[i]), - details ? details->caption : "", - font_id, - SOFTKEY_BUTTON_W, SOFTKEY_BUTTON_H - ); - base_gauge_add_child(BASE_GAUGE(self), BASE_GAUGE(&(self->buttons[i])), x , 0); - } - - return self; -} - -void softkey_bar_set_model(SoftkeyBar *self, SoftkeyModel *model) -{ - self->model = model; - - for(int i = 0, x = 2; i < N_SOFTKEYS; i++, x += SOFTKEY_BUTTON_W){ - SoftkeyDetails *details = self->model - ? softkey_model_get_details_at(self->model, i) - : NULL; - button_set_caption(BUTTON(&(self->buttons[i])), details ? details->caption : ""); - } - BASE_GAUGE(self)->dirty = true; /*TODO: Check if that is needed*/ -} - -void softkey_bar_push_model(SoftkeyBar *self, SoftkeyModel *model) -{ - model->prev = self->model; - softkey_bar_set_model(self, model); -} - -bool softkey_bar_pop_model(SoftkeyBar *self) -{ - SoftkeyModel *previous; - - if(!self->model) return false; - - previous = self->model->prev; - self->model->prev = NULL; - softkey_bar_set_model(self, previous); - - return true; -} - -static void softkey_bar_render(SoftkeyBar *self, Uint32 dt, RenderContext *ctx) -{ - base_gauge_fill(BASE_GAUGE(self), ctx, NULL, &(SDL_BLACK), false); -} - -/*Always return false, we do not care about focus*/ -static bool softkey_bar_handle_event(SoftkeyBar *self, SDL_KeyboardEvent *event) -{ - if(!self->model) return false; - if(event->state != SDL_PRESSED && event->state != SDL_RELEASED) return false; - - intf8_t idx = softkey_bar_key_to_button_index(event); - if(idx < 0) return false; - - SoftkeyDetails *details = softkey_model_get_details_at(self->model, idx); - if(!details) return false; - - if(event->state == SDL_PRESSED){ - softkey_set_state(&(self->buttons[idx]), SOFTKEY_STATE_PRESSED); -// printf("%s: Pressed\n",__FUNCTION__); - return true; - } - - softkey_set_state(&(self->buttons[idx]), SOFTKEY_STATE_RELEASED); -// printf("%s: Released\n",__FUNCTION__); - /*TODO: Animate the button press, change state before doing the actions*/ - if(details->type == SOFTKEY_TYPE_REGULAR){ - //invoke callback - }else if(details->type == SOFTKEY_TYPE_SEGUE){ - softkey_bar_push_model(self, details->action.next); - }else if(details->type == SOFTKEY_TYPE_BACK){ - softkey_bar_pop_model(self); - } - - return false; -} - -static intf8_t softkey_bar_key_to_button_index(SDL_KeyboardEvent *event) -{ - switch(event->keysym.sym){ - case SDLK_F1: return 1; - case SDLK_F2: return 2; - case SDLK_F3: return 3; - case SDLK_F4: return 4; - case SDLK_F5: return 5; - case SDLK_F6: return 6; - case SDLK_F7: return 7; - case SDLK_F8: return 8; - case SDLK_F9: return 9; - case SDLK_F10: return 10; - case SDLK_F11: return 11; - case SDLK_F12: return 12; - } - return -1; -} diff --git a/widgets/softkey-bar.h b/widgets/softkey-bar.h deleted file mode 100644 index 18b6aaf..0000000 --- a/widgets/softkey-bar.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef SOFTKEY_BAR_H_ /*Wihtout the trailing underscore guard*/ -#define SOFTKEY_BAR_H_ /*would conflict with the height define*/ - -#include "base-widget.h" -#include "softkey.h" -#include "softkey-model.h" -#include "resource-manager.h" - -#define N_SOFTKEYS 12 - -typedef struct { - BaseWidget super; - - Softkey buttons[N_SOFTKEYS]; - - SoftkeyModel *model; -}SoftkeyBar; - - -SoftkeyBar *softkey_bar_new(FontResource font_id, SoftkeyModel *model); -SoftkeyBar *softkey_bar_init(SoftkeyBar *self, SoftkeyModel *model, FontResource font_id, int w, int h); - -void softkey_bar_set_model(SoftkeyBar *self, SoftkeyModel *model); - -void softkey_bar_push_model(SoftkeyBar *self, SoftkeyModel *model); -bool softkey_bar_pop_model(SoftkeyBar *self); -#endif /* SOFTKEY_BAR_H_ */ diff --git a/widgets/softkey-model.c b/widgets/softkey-model.c deleted file mode 100644 index 7cf6f29..0000000 --- a/widgets/softkey-model.c +++ /dev/null @@ -1,35 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include - -#include "softkey-model.h" - - -SoftkeyModel *softkey_model_init(SoftkeyModel *self, SoftkeyModelOps *ops) -{ - self->ops = ops; - - return self; -} - -SoftkeyModel *softkey_model_dispose(SoftkeyModel *self) -{ - if(self->ops->dispose) - self->ops->dispose(self); - - return self; -} - - -SoftkeyDetails *softkey_model_get_details_at(SoftkeyModel *self, uint_fast8_t index) -{ - if(index < 0 || index > 11) return NULL; - - return self->ops->get_details_at(self, index); -} - diff --git a/widgets/softkey-model.h b/widgets/softkey-model.h deleted file mode 100644 index 99cadff..0000000 --- a/widgets/softkey-model.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef SOFTKEY_MODEL_H -#define SOFTKEY_MODEL_H - -#include "softkey.h" -#include - -#define SOFTKEY_CAPTION_MAX 9 /*8 chars plus NUL*/ - -typedef struct _SoftkeyModel SoftkeyModel; - -typedef enum {SOFTKEY_TYPE_REGULAR, SOFTKEY_TYPE_SEGUE, SOFTKEY_TYPE_BACK} SoftkeyType; -typedef struct{ - SoftkeyState state; - SoftkeyType type; - union{ - void (*clickedCallback)(void); - SoftkeyModel *next; - }action; - char caption[SOFTKEY_CAPTION_MAX]; -}SoftkeyDetails; - -#define SOFTKEY_DETAILS(self) ((SoftkeyDetails*)(self)) - -typedef void* (*DisposeFunc)(void *self); /*TODO: Move upwards*/ -typedef SoftkeyDetails* (*GetButtonDetailsAtFunc)(SoftkeyModel *self, uint_fast8_t index); - -typedef struct{ - DisposeFunc dispose; - GetButtonDetailsAtFunc get_details_at; -}SoftkeyModelOps; - -typedef struct _SoftkeyModel{ - SoftkeyModelOps *ops; - SoftkeyModel *prev; -}SoftkeyModel; - -#define SOFTKEY_MODEL(self) ((SoftkeyModel *)(self)) -#define SOFTKEY_MODEL_OPS(self) ((SoftkeyModelOps *)(self)) - - -SoftkeyModel *softkey_model_init(SoftkeyModel *self, SoftkeyModelOps *ops); -SoftkeyModel *softkey_model_dispose(SoftkeyModel *self); - -SoftkeyDetails *softkey_model_get_details_at(SoftkeyModel *self, uint_fast8_t index); -#endif /* SOFTKEY_MODEL_H */ diff --git a/widgets/softkey.c b/widgets/softkey.c deleted file mode 100644 index d1517f6..0000000 --- a/widgets/softkey.c +++ /dev/null @@ -1,123 +0,0 @@ -#include - -#include "base-gauge.h" -#include "base-widget.h" -#include "button.h" -#include "softkey.h" -#include "text-gauge.h" - - -static BaseWidgetOps softkey_ops = { 0 }; - - -static inline void softkey_draw_border(Softkey *self, Uint32 dt, RenderContext *ctx); -static void softkey_render(Softkey *self, Uint32 dt, RenderContext *ctx); - -Softkey *softkey_new(const char *caption, FontResource font_id, int w, int h) -{ - Softkey *self; - - self = calloc(1, sizeof(Softkey)); - if(self){ - if(!softkey_init(self, caption, font_id, w, h)){ - return base_gauge_free(BASE_GAUGE(self)); - } - } - return self; -} - -Softkey *softkey_init(Softkey *self, const char *caption, FontResource font_id, int w, int h) -{ - Button *super = button_init(BUTTON(self), - caption, font_id, - SDL_WHITE, (SDL_Color){32, 32, 32, SDL_ALPHA_OPAQUE}, - w, h - ); - if(!super) return NULL; - - if(!softkey_ops.super.render){ - memcpy(&softkey_ops, BUTTON(self)->super.super.ops, sizeof(BaseWidgetOps)); - BASE_GAUGE_OPS(&softkey_ops)->render = (RenderFunc)softkey_render; - } - BASE_GAUGE(self)->ops = BASE_GAUGE_OPS(&softkey_ops); - - /*Offsets the internal TextGauge to account for (uneven) borders*/ - base_gauge_move_by(BASE_GAUGE(BUTTON(self)->text), 1, 2); - - return self; -} - - -void softkey_set_state(Softkey *self, SoftkeyState state) -{ - if(self->state == state) return; - - self->state = state; - switch(self->state){ - case SOFTKEY_STATE_DISABLED: - button_set_color(BUTTON(self), (SDL_Color){64, 64, 64, SDL_ALPHA_OPAQUE}, TEXT_COLOR); - button_set_color(BUTTON(self), (SDL_Color){32, 32, 32, SDL_ALPHA_OPAQUE}, BACKGROUND_COLOR); - break; - case SOFTKEY_STATE_PRESSED: - button_set_color(BUTTON(self), (SDL_Color){32, 32, 32, SDL_ALPHA_OPAQUE}, TEXT_COLOR); - button_set_color(BUTTON(self), (SDL_Color){128, 128, 128, SDL_ALPHA_OPAQUE}, BACKGROUND_COLOR); - break; - case SOFTKEY_STATE_RELEASED: - button_set_color(BUTTON(self), SDL_WHITE, TEXT_COLOR); - button_set_color(BUTTON(self), (SDL_Color){32, 32, 32, SDL_ALPHA_OPAQUE}, BACKGROUND_COLOR); - break; - } -} - - -static void softkey_render(Softkey *self, Uint32 dt, RenderContext *ctx) -{ - base_gauge_fill(BASE_GAUGE(self), ctx, NULL, &(BUTTON(self)->text->bg_color), false); - softkey_draw_border(self, dt, ctx); -} - -static inline void softkey_draw_border(Softkey *self, Uint32 dt, RenderContext *ctx) -{ - /*TODO: Add the first top white line*/ - SDL_Rect top = (SDL_Rect){ - .x = 0, - .y = 0, - .w = base_gauge_w(BASE_GAUGE(self)), - .h = 1 - }; - SDL_Rect top_second = (SDL_Rect){ - .x = 0, - .y = 1, - .w = base_gauge_w(BASE_GAUGE(self)), - .h = 1 - }; - - SDL_Rect left = (SDL_Rect){ - .x = 0, - .y = 1, - .w = 1, - .h = base_gauge_h(BASE_GAUGE(self)) - 1 /*TODO: Fix potential overdrawing, i.e a gauge can draw out of its area*/ - }; - SDL_Rect right = (SDL_Rect){ - .x = base_gauge_w(BASE_GAUGE(self)) - 1, - .y = 1, - .w = 1, - .h = base_gauge_h(BASE_GAUGE(self)) - 1 - }; - - - if(self->state == SOFTKEY_STATE_RELEASED){ - base_gauge_fill(BASE_GAUGE(self), ctx, &top, &SDL_WHITE, false); - base_gauge_fill(BASE_GAUGE(self), ctx, &top_second, &SDL_LIGHTGREY, false); - base_gauge_fill(BASE_GAUGE(self), ctx, &left, &SDL_LIGHTGREY, false); - base_gauge_fill(BASE_GAUGE(self), ctx, &right, &SDL_BLACK, false); - }else if(self->state == SOFTKEY_STATE_PRESSED){ - SDL_Rect pre_left = left; - left.x++; - base_gauge_fill(BASE_GAUGE(self), ctx, &top, &SDL_GREY, false); - base_gauge_fill(BASE_GAUGE(self), ctx, &top_second, &SDL_BLACK, false); - base_gauge_fill(BASE_GAUGE(self), ctx, &pre_left, &SDL_GREY, false); - base_gauge_fill(BASE_GAUGE(self), ctx, &left, &SDL_BLACK, false); - base_gauge_fill(BASE_GAUGE(self), ctx, &right, &SDL_WHITE, false); - } -} diff --git a/widgets/softkey.h b/widgets/softkey.h deleted file mode 100644 index 3420cc6..0000000 --- a/widgets/softkey.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef SOFTKEY_H - -#include "button.h" - -typedef enum{SOFTKEY_STATE_RELEASED, SOFTKEY_STATE_PRESSED, SOFTKEY_STATE_DISABLED } SoftkeyState; - -typedef struct { - Button super; - - SoftkeyState state; -}Softkey; - - -Softkey *softkey_new(const char *caption, FontResource font_id, int w, int h); -Softkey *softkey_init(Softkey *self, const char *caption, FontResource font_id, int w, int h); - -void softkey_set_state(Softkey *self, SoftkeyState state); -#define SOFTKEY_H -#endif /* SOFTKEY_H */ diff --git a/widgets/text-box.c b/widgets/text-box.c deleted file mode 100644 index 9bbf5ca..0000000 --- a/widgets/text-box.c +++ /dev/null @@ -1,409 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#include -#include -#include -#include -#include - -#include "SDL_pcf.h" -#include "base-gauge.h" -#include "base-widget.h" -#include "resource-manager.h" -#include "sdl-colors.h" - -#include "text-box.h" -#define TEXT_INCREMENT 10 - -static void kill_duplicates(char *base, size_t len); - -static bool text_box_validate_font(TextBox *self); - -static void text_box_render(TextBox *self, Uint32 dt, RenderContext *ctx); -static void text_box_update(TextBox *self); -static TextBox *text_box_dispose(TextBox *self); -static bool text_box_handle_event(TextBox *self, SDL_KeyboardEvent *event); - -static BaseWidgetOps text_box_ops ={ - .super.render = (RenderFunc)text_box_render, - .super.update_state = (StateUpdateFunc)text_box_update, - .super.dispose = (DisposeFunc)text_box_dispose, - .handle_event = (EventHandlerFunc)text_box_handle_event -}; - -TextBox *text_box_new(FontResource font_id, int width, int height) -{ - TextBox *self; - - self = calloc(1, sizeof(TextBox)); - if(self){ - if(!text_box_init(self, font_id, width, height)) - return base_gauge_free(BASE_GAUGE(self)); - } - return self; -} - -TextBox *text_box_init(TextBox *self, FontResource font_id, int width, int height) -{ - base_widget_init(BASE_WIDGET(self), - &text_box_ops, - width, height - ); - - self->alen = TEXT_INCREMENT; - self->text = calloc(self->alen, sizeof(char)); - if(!self->text) - return NULL; - self->text[0] = 32; - self->tlen = 2; - - self->font_id = font_id; - self->alen = TEXT_INCREMENT; - - PCF_Font *font; - font = resource_manager_get_font(self->font_id); - size_t nchars = ceilf((BASE_GAUGE(self)->frame.w*1.0)/PCF_FontCharWidth(font)); - - /* We need one more when scrolled: a 4-chars wide textbox can display - * 1 char partly, 3 chars and 1 more char partly with first width + last width - * = 1 full char width*/ - self->state.apatches = nchars+1; - self->state.patches = malloc(sizeof(PCF_StaticFontPatch)*self->state.apatches); - BASE_GAUGE(self)->dirty = true; - return self; -} - -static TextBox *text_box_dispose(TextBox *self) -{ - if(self->text) - free(self->text); - if(self->allowed_chars) - free(self->allowed_chars); - if(self->sfont) - PCF_StaticFontUnref(self->sfont); - if(self->state.patches) - free(self->state.patches); - return self; -} - -bool text_box_set_allowed_chars(TextBox *self, bool keep_order, int nsets, ...) -{ - char *tmp; - size_t tlen; - va_list ap; - - tlen = 0; - va_start(ap, nsets); - for(int i = 0; i < nsets; i++){ - tmp = va_arg(ap, char*); - tlen += strlen(tmp); - } - va_end(ap); - - char *iter; - self->nallowed_chars = tlen; - self->allowed_chars = calloc(self->nallowed_chars + 1, sizeof(char)); - - iter = self->allowed_chars; - va_start(ap, nsets); - for(int i = 0; i < nsets; i++){ - tmp = va_arg(ap, char*); - strcpy(iter, tmp); - iter += strlen(tmp); - } - - if(!keep_order){ - qsort(self->allowed_chars, - self->nallowed_chars, sizeof(char), - charcmp - ); - filter_dedup(self->allowed_chars, self->nallowed_chars); - }else{ - kill_duplicates(self->allowed_chars, self->nallowed_chars); - } - - return text_box_validate_font(self); -} - - -/** - * @param text should not have leading or trailing spaces - * - */ -bool text_box_set_text(TextBox *self, const char *text) -{ - int ntlen; - - if(text == NULL){ - self->text[0] = 32; - self->tlen = 2; - self->current_index = 0; - self->text_size = (SDL_Rect){0,0,0,0}; - BASE_GAUGE(self)->dirty = true; - return true; - } - - ntlen = strlen(text); - if((ntlen+1) >= self->alen){ - size_t nalen; - char *tmp; - nalen = ceilf((ntlen+1)*1.0f/TEXT_INCREMENT); - nalen *= TEXT_INCREMENT; - tmp = realloc(self->text, nalen); - if(!tmp) - return false; - self->text = tmp; - self->alen = nalen; - } - strncpy(self->text, text, ntlen+1); - self->tlen = ntlen+1; - - if(!text_box_validate_font(self)) - return false; - PCF_StaticFontGetSizeRequestRect(self->sfont, self->text, false, &(self->text_size)); - - return true; -} - - -bool text_box_move_cursor(TextBox *self, int_fast8_t direction) -{ - if(direction > 0){ - /* 0: a char, 1: \0, tlen=2 - * As tlen includes that last NULL byte, the last char of the string is - * NOT tlen-1, but tlen-2*/ - if(self->current_index == self->tlen-2){ /*We are on the last char*/ - if(self->current_index >= self->alen-2){ - return false; /*TODO: Grow*/ - } - - if(self->text[self->current_index] == ' '){ - if(self->current_index == 0) - return false; /*Can't move left if first char is space*/ - if(self->text[self->current_index-1] == ' ') - return false; /*Can't move left if previous char is also space*/ - } - - self->current_index++; - self->text[self->current_index] = self->current_index > 0 - ? self->text[self->current_index-1] - : 32; - self->text[self->current_index+1] = '\0'; - self->tlen++; - PCF_StaticFontGetSizeRequestRect(self->sfont, self->text, false, &(self->text_size)); - }else{ - self->current_index++; - } - }else if(direction < 0 && self->current_index > 0){ - if(self->text[self->current_index] == ' '){ - while(self->current_index > 0 && self->text[self->current_index] == ' '){ - self->text[self->current_index] = '\0'; - self->current_index--; - self->tlen--; - } - }else{ - self->current_index--; - } - }else{ - return false; - } - - BASE_GAUGE(self)->dirty = true; - return true; -} - -void text_box_cycle_char(TextBox *self, int_fast8_t direction) -{ - if(self->allowed_chars){ - size_t ac_index; /*index in the allowed char set*/ - char *ac_ptr; - - ac_index = 0; - if(self->text[self->current_index] != '\0'){ - ac_ptr = strchr(self->allowed_chars, self->text[self->current_index]); - if(ac_ptr) - ac_index = (size_t)(ac_ptr - self->allowed_chars); - } - - /*TODO: Have a utility function that makes a value go round*/ - if(ac_index == 0 && direction < 0) - ac_index = self->nallowed_chars-1; - if(ac_index == (self->nallowed_chars-1) && direction > 0) - ac_index = 0; - - ac_index += direction; - - self->text[self->current_index] = self->allowed_chars[ac_index]; - }else{ //ASCII - self->text[self->current_index] += direction; /*will loop over*/ - if(self->text[self->current_index] >= 127) /*TODO: Modulo?*/ - self->text[self->current_index] = 32; - } - BASE_GAUGE(self)->dirty = true; - - if(self->changed_callback) - self->changed_callback(self, self->userdata); -} - -bool text_box_release_focus(TextBox *self) -{ - BASE_GAUGE(self)->dirty = true; - return false; -} - -static void text_box_update(TextBox *self) -{ - TextBoxState *state; - - state = &(self->state); - int charx = self->current_index * PCF_StaticFontCharWidth(self->sfont); - /*no need to -1 *both* for cmp*/ - int outx = charx + PCF_StaticFontCharWidth(self->sfont); /*first pixel out of glyph*/ - - if(outx > state->startx + BASE_GAUGE(self)->frame.w){ - state->startx = (outx-1) - (BASE_GAUGE(self)->frame.w-1); - }else if(charx < state->startx){ - state->startx = charx; - } - - size_t ibegin; /*string indices*/ - ibegin = state->startx / PCF_StaticFontCharWidth(self->sfont); - state->first_index = ibegin; - - SDL_Rect tarea = BASE_GAUGE(self)->frame; - state->npatches = PCF_StaticFontPreWriteStringOffset( - self->sfont, - self->tlen-1, - self->text+ibegin, - false, - &tarea, - state->startx * -1, 0, - state->apatches, state->patches - ); - - BASE_GAUGE(self)->dirty = false; -} - - -static void text_box_render(TextBox *self, Uint32 dt, RenderContext *ctx) -{ - for(int i = 0; i < self->state.npatches; i++){ - if(self->state.first_index + i == self->current_index && BASE_WIDGET(self)->has_focus){ - /*TODO: PCF_StaticFontPatch(Src|Dst)Rect */ - base_gauge_fill(BASE_GAUGE(self), ctx, &(SDL_Rect){ - self->state.patches[i].dst.x, - self->state.patches[i].dst.y, - self->state.patches[i].src.w, - self->state.patches[i].src.h - }, &SDL_RED, false - ); - } - if(self->state.patches[i].src.x < 0) continue; - - base_gauge_draw_static_font_rect_patch(BASE_GAUGE(self), ctx, - self->sfont, - &self->state.patches[i] - ); - } - - base_widget_draw_outline(BASE_WIDGET(self), ctx); -} - - -static bool text_box_handle_event(TextBox *self, SDL_KeyboardEvent *event) -{ - if(event->state != SDL_PRESSED) return true; - - switch(event->keysym.sym){ - case SDLK_UP: - text_box_cycle_char(self, -1); - break; - case SDLK_DOWN: - text_box_cycle_char(self, +1); - break; - case SDLK_LEFT: - text_box_move_cursor(self, -1); - break; - case SDLK_RIGHT: - text_box_move_cursor(self, +1); - break; - case SDLK_RETURN: - return text_box_release_focus(self); - break; - } - return true; -} - -static bool text_box_validate_font(TextBox *self) -{ - if(self->sfont){ - if(PCF_StaticFontCanWrite(self->sfont, NULL, self->text)){ - if(self->allowed_chars){ - if(PCF_StaticFontCanWrite(self->sfont, NULL, self->allowed_chars)) - return true; - }else{ - return true; - } - - } - /*We get here only if we have a font and that font can't write self->text*/ - PCF_StaticFontUnref(self->sfont); - } - - if(self->allowed_chars){ - self->sfont = resource_manager_get_static_font(self->font_id, - &SDL_WHITE, - 2, - self->text, - self->allowed_chars - ); - }else{ - self->sfont = resource_manager_get_static_font(self->font_id, - &SDL_WHITE, - 1, - self->text - ); - } - if(!self->sfont) - return false; - - PCF_StaticFontCreateTexture(self->sfont); - return self->sfont->texture != NULL; -} - -/* - * Remove duplicates characters from @p base, while keeping the order. - * When duplicates are found, only the first occurence is kept. - * - * This function is slower than filter_dedup but doesn't need sorting - * and thus can preserve original ordering. - * - * @param base The string to filter - * @param len THe string len, -1 to have the function compute it. - */ -static void kill_duplicates(char *base, size_t len) -{ - len = len > -1 ? len : strlen(base); - - for(int i = 0; i < len; i++){ - for(int j = i+1; j < len; j++){ - if(base[j] == base[i]) - base[j] = '\0'; - } - } - - for(int i = 0; i < len; i++){ - if(base[i] == '\0'){ - /*look for next real char*/ - int next; - for(next = i; next < len && base[next] == '\0'; next++); - for(int j = next; j < len; j++) - base[i+(j-next)] = base[j]; - } - } -} diff --git a/widgets/text-box.h b/widgets/text-box.h deleted file mode 100644 index d10ceff..0000000 --- a/widgets/text-box.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Samuel Cuella - * - * This file is part of SoFIS - an open source EFIS - * - * SPDX-License-Identifier: GPL-2.0-only - */ -#ifndef TEXT_BOX_H -#define TEXT_BOX_H -#include -#include -#include - -#include "SDL_pcf.h" -#include "base-widget.h" -#include "resource-manager.h" - -typedef struct _TextBox TextBox; - -typedef void (*TextBoxTextChanged)(TextBox *self, void *userdata); - -typedef struct{ - PCF_StaticFontPatch *patches; - size_t npatches; - size_t apatches; - size_t first_index; - - Uint32 startx; /*offset in the virtual rectangle*/ -}TextBoxState; - -typedef struct _TextBox{ - BaseWidget super; - - FontResource font_id; - PCF_StaticFont *sfont; - - /*TODO: GenericArray/StringBuilder*/ - char *text; - size_t alen; - size_t tlen; /*text len, INCLUDING last ''\0' byte*/ - - size_t current_index; - - char *allowed_chars; - size_t nallowed_chars; - - SDL_Rect text_size; /*Virtual rectangle with the whole text*/ - - TextBoxState state; - - TextBoxTextChanged changed_callback; - void *userdata; -}TextBox; - -TextBox *text_box_new(FontResource font_id, int width, int height); -TextBox *text_box_init(TextBox *self, FontResource font_id, int width, int height); - -bool text_box_set_text(TextBox *self, const char *text); -bool text_box_set_allowed_chars(TextBox *self, bool keep_order, int nsets, ...); - -bool text_box_move_cursor(TextBox *self, int_fast8_t direction); -void text_box_cycle_char(TextBox *self, int_fast8_t direction); - -#endif /* TEXT_BOX_H */