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