1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2025-04-20 12:19:11 +02:00

Compare commits

...

126 Commits

Author SHA1 Message Date
372f2966bb Properly print the tag name on big-edian systems 2025-04-17 20:58:27 +02:00
1aa0fa4be4 Fixed Qt5 build 2025-04-17 20:37:30 +02:00
f4e19d0917 Multiple S-57 files parse optimizations 2025-04-17 20:25:12 +02:00
91376fd609 Make sure all fields have their definitions 2025-04-17 08:43:23 +02:00
92b2fbaf04 Fixed ISO8211 parser error handling 2025-04-17 07:42:45 +02:00
a21096a0a9 Added Vakaros VKX files support info 2025-04-16 08:59:31 +02:00
920cf03d1b
Translated using Weblate (German)
Currently translated at 100.0% (492 of 492 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/de/
2025-04-15 07:18:18 +02:00
72155beb6b
Translated using Weblate (Czech)
Currently translated at 100.0% (492 of 492 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/cs/
2025-04-15 07:16:48 +02:00
99 efi
88acc78e1c
Translated using Weblate (Hungarian)
Currently translated at 100.0% (492 of 492 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/hu/
2025-04-14 19:03:04 +02:00
Babos Gábor
1583794329
Translated using Weblate (Hungarian)
Currently translated at 100.0% (492 of 492 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/hu/
2025-04-14 19:03:03 +02:00
Максим Горпиніч
beb2f6d70c
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (492 of 492 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/uk/
2025-04-14 19:03:02 +02:00
Åke Engelbrektson
afd3a09f50
Translated using Weblate (Swedish)
Currently translated at 100.0% (492 of 492 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/sv/
2025-04-14 19:03:02 +02:00
Cloud Esp
2a247a2a38
Translated using Weblate (French)
Currently translated at 100.0% (492 of 492 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/fr/
2025-04-14 19:03:01 +02:00
44af6eea4d Vakaros VKX MacOS desktop integration 2025-04-14 09:31:10 +02:00
40c396a8c8 Localization update 2025-04-13 18:13:55 +02:00
5018aecb42 Added Vakaros VKX support info 2025-04-13 18:12:16 +02:00
a2d56236b6 Version++ 2025-04-13 18:10:35 +02:00
b20a6cd479 Vakaros VKX Windows desktop integration 2025-04-13 17:55:39 +02:00
7bbf6fba97 Vakaros VKX Linux desktop integration 2025-04-13 17:41:33 +02:00
d2ac9f2ee6 Added support for Vakaros VKX files 2025-04-12 13:16:36 +02:00
ERYpTION
fa344e94e4
Translated using Weblate (Danish)
Currently translated at 100.0% (491 of 491 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/da/
2025-04-08 09:01:40 +02:00
raf
dd53293229
Translated using Weblate (Catalan)
Currently translated at 100.0% (491 of 491 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/ca/
2025-03-25 12:29:40 +01:00
355f451e5c Add "office" as used in OpenAndroMaps as an equivalent to Mapsforge's "civic" 2025-03-21 22:06:50 +01:00
0b61fb0470 Use jom for Windows CI builds 2025-03-21 06:55:21 +01:00
af18c98a03 Update the nuber of cores acording to the latest GitHub runners state 2025-03-21 06:27:33 +01:00
e9a8112196 Fixed error handling 2025-03-21 05:56:17 +01:00
Nikolay Korotkiy
bca335d4b2
Translated using Weblate (Esperanto)
Currently translated at 91.2% (448 of 491 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/eo/
2025-03-20 22:55:09 +01:00
Nikolay Korotkiy
f3b1fa8eb7
Translated using Weblate (Russian)
Currently translated at 100.0% (491 of 491 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/ru/
2025-03-20 22:55:09 +01:00
Nikolay Korotkiy
fac377e746
Translated using Weblate (Finnish)
Currently translated at 96.7% (475 of 491 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/fi/
2025-03-20 22:55:09 +01:00
7184c691d3 Fixed possible null pointer dereferences 2025-03-19 08:11:49 +01:00
381ab1516d Do not draw special type buildings multiple times.
Use the new "exclude" rule to improve performance by not drawing
the civic/church buildings multipe times.
2025-03-19 01:38:04 +01:00
cf84680bc6 Revert "Use jom in Windows CI builds"
This reverts commit 38abffda178b7695b1d2db7fff815a4f6411ef7a.
2025-03-17 22:47:44 +01:00
Hosted Weblate
74e322860f
Merge branch 'origin/master' into Weblate. 2025-03-17 22:33:21 +01:00
38abffda17 Use jom in Windows CI builds 2025-03-17 22:33:12 +01:00
99 efi
304d4f770e
Translated using Weblate (Hungarian)
Currently translated at 100.0% (491 of 491 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/hu/
2025-03-17 16:17:37 +01:00
Максим Горпиніч
739564955e
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (491 of 491 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/uk/
2025-03-17 15:17:05 +01:00
Cloud Esp
4e45cf6d40
Translated using Weblate (French)
Currently translated at 100.0% (491 of 491 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/fr/
2025-03-17 15:17:05 +01:00
Hosted Weblate
644e14947d
Merge branch 'origin/master' into Weblate. 2025-03-17 09:00:35 +01:00
c171e8088c
Added Velocitek VTK support info 2025-03-17 09:00:32 +01:00
Hosted Weblate
431357b08d
Merge branch 'origin/master' into Weblate. 2025-03-17 08:41:50 +01:00
af03a85fdb Added missing VTK icns icon 2025-03-17 08:41:20 +01:00
Åke Engelbrektson
003bdd8814
Translated using Weblate (Swedish)
Currently translated at 100.0% (491 of 491 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/sv/
2025-03-17 08:01:21 +01:00
91c0e2a83d German translation update 2025-03-17 07:43:05 +01:00
496a474bd2 Czech translation update 2025-03-17 07:42:35 +01:00
f1b7d57027 Lcalization update 2025-03-17 07:40:10 +01:00
2e4e702640 Fixed speed values conversion 2025-03-16 22:33:26 +01:00
9d3cdbbd42 Velocitek VTK MacOS desktop integration 2025-03-16 22:15:37 +01:00
0e329f4b22 Added Velocitek VTK Windows desktop integration 2025-03-16 17:53:00 +01:00
2041cc7ff5 Added Velocitek VTK files Linux desktop integration 2025-03-16 17:37:37 +01:00
8169015f70 Added missing trunk roads names 2025-03-16 17:32:36 +01:00
28f55b7e0d Added support for Velocitek VTK files 2025-03-16 17:17:09 +01:00
912a00c80e Cosmetics 2025-03-16 17:15:33 +01:00
8de6bbe4fb Fixed maximal speed info
Display the maximum of all primary graphs, not the maximum of all graphs.
2025-03-16 17:14:14 +01:00
f34d6b0540 Fixed wrong oneway icon filename 2025-03-16 17:11:13 +01:00
Максим Горпиніч
2eb527f2f3
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (490 of 490 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/uk/
2025-03-11 20:01:29 +01:00
94785ee2ec Added support for the "exclude" theme rules added in recent Mapsforge versions 2025-03-11 07:34:31 +01:00
a2f1ef7572 Silence MSVC C4018 warnings 2025-03-08 18:06:20 +01:00
7731cfaa4f Version++ 2025-03-08 18:05:44 +01:00
a9572d05fe Fixed broken sector lights rendering after recent code changes 2025-03-08 04:27:40 +01:00
fdd5d46c03 Refactoring 2025-03-08 04:21:55 +01:00
39ed798a48 Some more code cleanup 2025-03-08 03:58:28 +01:00
64b29f8aac Code cleanup 2025-03-08 03:43:09 +01:00
8ea84c5c86 Fixed microoptimization 2025-03-08 03:32:05 +01:00
db6e891c30 Levels overlay fixes/tweaks 2025-03-07 21:57:24 +01:00
d91acb66f2 Only render the levels that need to be rendered 2025-03-07 21:13:54 +01:00
Hosted Weblate
3804e8ca7c
Merge branch 'origin/master' into Weblate. 2025-03-06 07:56:24 +01:00
2595926b7f Overlay two consecutive layers when drawing ENC atlases 2025-03-06 07:55:01 +01:00
Hosted Weblate
0d38603332
Merge branch 'origin/master' into Weblate. 2025-03-03 21:46:05 +01:00
66693cd5c9 Added missing const specifier 2025-03-03 21:44:08 +01:00
4eec328dbf Cosmetics 2025-03-03 21:43:39 +01:00
Bora Atıcı
4121c99e56
Translated using Weblate (Turkish)
Currently translated at 100.0% (490 of 490 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/tr/
2025-03-03 12:28:28 +01:00
a3f1d25d63 Improved ENC fishing farms rendering 2025-03-02 17:44:04 +01:00
6c80d89c89 Distinguish white/yellow lights on ENC charts 2025-03-02 08:39:22 +01:00
7cf957a48d Cosmetics 2025-03-02 07:58:23 +01:00
792ede2a96 Code cleanup 2025-03-01 09:49:33 +01:00
99 efi
cee53eab90
Translated using Weblate (Hungarian)
Currently translated at 100.0% (490 of 490 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/hu/
2025-02-27 16:00:46 +01:00
Cloud Esp
1f81d867d5
Translated using Weblate (French)
Currently translated at 100.0% (490 of 490 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/fr/
2025-02-26 19:48:09 +01:00
Åke Engelbrektson
39edcd4a1e
Translated using Weblate (Swedish)
Currently translated at 100.0% (490 of 490 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/sv/
2025-02-26 08:36:50 +01:00
2808768f13
Added 70mai GPS log files support info 2025-02-26 07:49:41 +01:00
451782ce20 Be more strict when parsing the TXT files 2025-02-26 07:44:33 +01:00
5d1ba90f09 German translation update 2025-02-25 21:15:16 +01:00
60fd7fb7c3 Czech translation update 2025-02-25 21:14:55 +01:00
7249c85a02 Localization update 2025-02-25 21:08:03 +01:00
099ce0ad6c 70mai GPS logs Windows desktop integration 2025-02-25 21:05:49 +01:00
b1aa32d23b 70mai GPS logs MacOS desktop integration 2025-02-25 21:05:13 +01:00
1f31a5d6c5 70mai GPS logs Linux desktop integration 2025-02-25 20:41:52 +01:00
044770bc84 Added support for 70mai dashcams GPS log files 2025-02-25 20:24:26 +01:00
c5f51e935e Limit maximal allowed CSV entries size 2025-02-25 20:23:01 +01:00
17ad10ba23 Fixed broken date ranges when there is no date in some data 2025-02-25 20:20:38 +01:00
f5f27c0212 Remove some more Qt < 5.15 hack 2025-02-24 13:34:17 +01:00
7e1bbbbd6a Version++ 2025-02-24 13:33:46 +01:00
71a757983f Some more obsolete stuff cleanup 2025-02-20 08:57:50 +01:00
cc7209ad70 Removed obsolete stuff 2025-02-20 08:53:04 +01:00
ba49497608 Code cleanup 2025-02-20 08:50:17 +01:00
48404ea43b Limit the sector lights ranges 2025-02-20 07:34:47 +01:00
b9fb9eece3 Use 10NM as the major/minor light threshold 2025-02-19 23:00:39 +01:00
0cac0369aa Distinguish major/minor lights 2025-02-19 22:49:19 +01:00
cdf198ec1d Fixed clazy warning 2025-02-19 22:48:12 +01:00
0896b54831 Improved marine lights presentation 2025-02-19 19:26:14 +01:00
9f1808274f Use Qt 6.8.2 for the OS X builds 2025-02-19 00:49:40 +01:00
5d2465cffc Remove all Qt5 < 5.15 workarounds.
Qt 5.15 is now the minimal required Qt version.
2025-02-19 00:20:18 +01:00
2ab7bff3f8 Cosmetics 2025-02-18 23:11:13 +01:00
060cfb574d Build both release and debug configurations on Linux 2025-02-18 22:44:55 +01:00
5c178b4088 Fixed debug builds 2025-02-18 22:24:43 +01:00
2f4a7f8053 Improved IMG marine style 2025-02-18 22:09:59 +01:00
5f1838ea30 Code cleanup 2025-02-18 22:09:16 +01:00
bdf75169c5 Read the marine lights info from the local navaid data if present 2025-02-17 22:45:24 +01:00
Hosted Weblate
9295f8f4a9
Merge branch 'origin/master' into Weblate. 2025-02-12 23:59:23 +01:00
3fc8e69ebb Removed unused metadata 2025-02-12 23:58:57 +01:00
4438bc8d52 Version++ 2025-02-12 23:46:36 +01:00
Hosted Weblate
f9e99fcc73
Merge branch 'origin/master' into Weblate. 2025-02-12 20:01:32 +01:00
Hosted Weblate
f494543e54
Merge branch 'origin/master' into Weblate. 2025-02-12 19:45:34 +01:00
Hosted Weblate
70936cafe3
Merge branch 'origin/master' into Weblate. 2025-02-12 19:14:09 +01:00
Hosted Weblate
74781d6462
Merge branch 'origin/master' into Weblate. 2025-02-12 19:06:11 +01:00
Hosted Weblate
466e8f2909
Merge branch 'origin/master' into Weblate. 2025-02-12 09:05:22 +01:00
Hosted Weblate
1c9dd610d5
Merge branch 'origin/master' into Weblate. 2025-02-12 01:55:34 +01:00
Hosted Weblate
538ec4f71b
Merge branch 'origin/master' into Weblate. 2025-02-11 08:13:28 +00:00
Hosted Weblate
9bb56032b0
Merge branch 'origin/master' into Weblate. 2025-02-11 08:25:54 +01:00
Hosted Weblate
c3e76e1d3d
Merge branch 'origin/master' into Weblate. 2025-02-10 23:36:45 +01:00
Hosted Weblate
766000458d
Merge branch 'origin/master' into Weblate. 2025-02-10 19:26:27 +00:00
Hosted Weblate
0d029636be
Merge branch 'origin/master' into Weblate. 2025-02-10 09:30:14 +01:00
Hosted Weblate
89b4bc56e4
Merge branch 'origin/master' into Weblate. 2025-02-09 23:01:10 +01:00
Hosted Weblate
08d09d038e
Merge branch 'origin/master' into Weblate. 2025-02-06 01:25:12 +01:00
Hosted Weblate
02c236a49e
Merge branch 'origin/master' into Weblate. 2025-02-06 01:11:17 +01:00
mtriau
f67c262292
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (488 of 488 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/zh_Hans/
2025-01-27 08:01:49 +01:00
mtriau
7cfd62ca97
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.7% (487 of 488 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/zh_Hans/
2025-01-26 07:10:38 +01:00
117 changed files with 7181 additions and 5754 deletions

View File

@ -1,4 +1,4 @@
version: 13.35.{build} version: 13.39.{build}
configuration: configuration:
- Release - Release
@ -8,6 +8,7 @@ image:
environment: environment:
NSISDIR: C:\Program Files (x86)\NSIS NSISDIR: C:\Program Files (x86)\NSIS
JOMDIR: C:\Qt\Tools\QtCreator\bin\jom
matrix: matrix:
- QTDIR: C:\Qt\5.15\msvc2019_64 - QTDIR: C:\Qt\5.15\msvc2019_64
OPENSSLDIR: C:\OpenSSL-v111-Win64\bin OPENSSLDIR: C:\OpenSSL-v111-Win64\bin
@ -17,14 +18,14 @@ environment:
install: install:
- cmd: |- - cmd: |-
set PATH=%QTDIR%\bin;%NSISDIR%;%PATH% set PATH=%QTDIR%\bin;%NSISDIR%;%JOMDIR%;%PATH%
call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat
build_script: build_script:
- cmd: |- - cmd: |-
lrelease gpxsee.pro lrelease gpxsee.pro
qmake gpxsee.pro qmake gpxsee.pro
nmake release jom release
md installer md installer
copy release\GPXSee.exe installer copy release\GPXSee.exe installer

View File

@ -43,7 +43,7 @@ jobs:
- name: Configure build - name: Configure build
run: qmake gpxsee.pro OPENSSL_PATH=android_openssl run: qmake gpxsee.pro OPENSSL_PATH=android_openssl
- name: Build project - name: Build project
run: make -j2 apk run: make -j4 apk
- name: Upload artifacts - name: Upload artifacts
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:

View File

@ -8,7 +8,10 @@ on:
jobs: jobs:
build: build:
name: GPXSee name: GPXSee
runs-on: ubuntu-20.04 runs-on: ubuntu-22.04
strategy:
matrix:
config: ['release', 'debug']
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
@ -19,6 +22,6 @@ jobs:
- name: Create localization - name: Create localization
run: lrelease gpxsee.pro run: lrelease gpxsee.pro
- name: Configure build - name: Configure build
run: qmake gpxsee.pro run: qmake CONFIG+=${{ matrix.config }} gpxsee.pro
- name: Build project - name: Build project
run: make -j2 run: make -j4

View File

@ -15,7 +15,7 @@ jobs:
- name: Install Qt - name: Install Qt
uses: jurplel/install-qt-action@v4 uses: jurplel/install-qt-action@v4
with: with:
version: '6.8.1' version: '6.8.2'
modules: qtpositioning qtserialport qtimageformats modules: qtpositioning qtserialport qtimageformats
- name: Create localization - name: Create localization
run: lrelease gpxsee.pro run: lrelease gpxsee.pro

View File

@ -5,7 +5,8 @@ GPS log file formats.
## Features ## Features
* Opens GPX, TCX, FIT, KML, NMEA, IGC, CUP, SIGMA SLF, Suunto SML, LOC, GeoJSON, * Opens GPX, TCX, FIT, KML, NMEA, IGC, CUP, SIGMA SLF, Suunto SML, LOC, GeoJSON,
OziExplorer (PLT, RTE, WPT), Garmin GPI&CSV, TomTom OV2&ITN, ONmove OMD/GHP, OziExplorer (PLT, RTE, WPT), Garmin GPI&CSV, TomTom OV2&ITN, ONmove OMD/GHP,
TwoNav (TRK, RTE, WPT), GPSDump WPT and geotagged JPEG files. TwoNav (TRK, RTE, WPT), GPSDump WPT, Velocitek VTK, Vakaros VKX, 70mai GPS logs
and geotagged JPEG files.
* Opens geo URIs (RFC 5870). * Opens geo URIs (RFC 5870).
* User-definable online maps (OpenStreetMap/Google tiles, WMTS, WMS, TMS, * User-definable online maps (OpenStreetMap/Google tiles, WMTS, WMS, TMS,
QuadTiles). QuadTiles).
@ -29,8 +30,8 @@ GPS log file formats.
## Build ## Build
Build requirements: Build requirements:
* Qt5 >= 5.11 or Qt6 >= 6.2 (Android builds require Qt6) * Qt5 >= 5.15 or Qt6 >= 6.2 (Android builds require Qt6)
* C++11 or newer compiler (tested: msvc2019, gcc 7.5.0, clang/Apple LLVM version * C++11 or newer compiler (tested: msvc2022, gcc 11, clang/Apple LLVM version
10.0.0) 10.0.0)
Build steps: Build steps:

View File

@ -214,10 +214,11 @@
</rule> </rule>
<!-- Buildings --> <!-- Buildings -->
<rule e="way" k="building" v="*"> <rule e="way" k="building" v="-|civic|office|cathedral|church|basilica">
<area fill="#dbd0b6" stroke="#cdccc4" stroke-width="0.1"/> <area fill="#dbd0b6" stroke="#cdccc4" stroke-width="0.1"/>
</rule> </rule>
<rule e="way" k="building" v="civic">
<rule e="way" k="building" v="civic|office">
<area fill="#cfc4b3" stroke="#cdccc4" stroke-width="0.1"/> <area fill="#cfc4b3" stroke="#cdccc4" stroke-width="0.1"/>
<rule e="way" k="*" v="*" zoom-min="16"> <rule e="way" k="*" v="*" zoom-min="16">
<caption fill="#000000" font-size="10" font-style="italic" k="name" stroke="#FFFFFF" stroke-width="2" priority="-10"/> <caption fill="#000000" font-size="10" font-style="italic" k="name" stroke="#FFFFFF" stroke-width="2" priority="-10"/>
@ -403,7 +404,7 @@
<rule e="way" k="*" v="*" zoom-min="14"> <rule e="way" k="*" v="*" zoom-min="14">
<pathText fill="#000000" font-size="10" k="name" priority="-5" stroke="#FFFFFF" stroke-width="2"/> <pathText fill="#000000" font-size="10" k="name" priority="-5" stroke="#FFFFFF" stroke-width="2"/>
<rule e="way" k="oneway" v="yes|true|1" zoom-min="16"> <rule e="way" k="oneway" v="yes|true|1" zoom-min="16">
<lineSymbol priority="-50" src=":/symbols/arrow.svg" symbol-width="16" symbol-height="8"/> <lineSymbol priority="-50" src=":/symbols/oneway.svg" symbol-width="16" symbol-height="8"/>
</rule> </rule>
</rule> </rule>
</rule> </rule>
@ -428,6 +429,12 @@
<line stroke="#f7d9a6" stroke-width="1" stroke-linecap="butt"/> <line stroke="#f7d9a6" stroke-width="1" stroke-linecap="butt"/>
</rule> </rule>
</rule> </rule>
<rule e="way" k="*" v="*" zoom-min="14">
<pathText fill="#000000" font-size="10" k="name" priority="-3" stroke="#FFFFFF" stroke-width="2"/>
<rule e="way" k="oneway" v="yes|true|1" zoom-min="16">
<lineSymbol priority="-50" src=":/symbols/oneway.svg" symbol-width="16" symbol-height="8"/>
</rule>
</rule>
</rule> </rule>
<rule e="way" k="highway" v="motorway|motorway_link"> <rule e="way" k="highway" v="motorway|motorway_link">
<rule e="way" k="tunnel" v="~|false|no"> <rule e="way" k="tunnel" v="~|false|no">

View File

@ -3,8 +3,7 @@ unix:!macx:!android {
} else { } else {
TARGET = GPXSee TARGET = GPXSee
} }
VERSION = 13.35 VERSION = 13.39
QT += core \ QT += core \
gui \ gui \
@ -118,7 +117,11 @@ HEADERS += src/common/config.h \
src/data/gpsdumpparser.h \ src/data/gpsdumpparser.h \
src/data/style.h \ src/data/style.h \
src/data/twonavparser.h \ src/data/twonavparser.h \
src/map/IMG/lights.h \ src/data/txtparser.h \
src/data/vkxparser.h \
src/data/vtkparser.h \
src/map/ENC/data.h \
src/map/IMG/light.h \
src/map/downloader.h \ src/map/downloader.h \
src/map/demloader.h \ src/map/demloader.h \
src/map/ENC/attributes.h \ src/map/ENC/attributes.h \
@ -344,6 +347,9 @@ SOURCES += src/main.cpp \
src/GUI/pngexportdialog.cpp \ src/GUI/pngexportdialog.cpp \
src/GUI/projectioncombobox.cpp \ src/GUI/projectioncombobox.cpp \
src/GUI/passwordedit.cpp \ src/GUI/passwordedit.cpp \
src/data/txtparser.cpp \
src/data/vkxparser.cpp \
src/data/vtkparser.cpp \
src/map/downloader.cpp \ src/map/downloader.cpp \
src/map/demloader.cpp \ src/map/demloader.cpp \
src/map/ENC/atlasdata.cpp \ src/map/ENC/atlasdata.cpp \
@ -559,7 +565,9 @@ win32 {
icons/formats/trk.ico \ icons/formats/trk.ico \
icons/formats/gemf.ico \ icons/formats/gemf.ico \
icons/formats/000.ico \ icons/formats/000.ico \
icons/formats/031.ico icons/formats/031.ico \
icons/formats/vtk.ico \
icons/formats/vkx.ico
DEFINES += _USE_MATH_DEFINES \ DEFINES += _USE_MATH_DEFINES \
NOGDI NOGDI
} }

View File

@ -216,6 +216,7 @@
<file alias="tanker-anchorage.png">icons/map/marine/tanker-anchorage.png</file> <file alias="tanker-anchorage.png">icons/map/marine/tanker-anchorage.png</file>
<file alias="nature-reserve-line.png">icons/map/marine/nature-reserve-line.png</file> <file alias="nature-reserve-line.png">icons/map/marine/nature-reserve-line.png</file>
<file alias="sanctuary-line.png">icons/map/marine/sanctuary-line.png</file> <file alias="sanctuary-line.png">icons/map/marine/sanctuary-line.png</file>
<file alias="fishing-farm.png">icons/map/marine/fishing-farm.png</file>
</qresource> </qresource>
<!-- Patterns (Mapsforge) --> <!-- Patterns (Mapsforge) -->

View File

@ -32,3 +32,5 @@ trk:#cccccc
gemf:#147085 gemf:#147085
000:#000000 000:#000000
031:#000000 031:#000000
vtk:#632433
vkx:#00ccff

BIN
icons/formats/vkx.icns Normal file

Binary file not shown.

BIN
icons/formats/vkx.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 KiB

BIN
icons/formats/vtk.icns Normal file

Binary file not shown.

BIN
icons/formats/vtk.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 286 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 294 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 215 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 393 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 190 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 189 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 382 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 238 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 219 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 330 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 401 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 286 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 261 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 217 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 243 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 239 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 275 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 266 B

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -15,8 +15,8 @@
<li>Opens GPX, TCX, FIT, KML, IGC, NMEA, SIGMA SLF, Suunto SML, LOC, <li>Opens GPX, TCX, FIT, KML, IGC, NMEA, SIGMA SLF, Suunto SML, LOC,
OziExplorer (PLT, WPT, RTE), GeoJSON, SeeYou CUP, OziExplorer (PLT, WPT, RTE), GeoJSON, SeeYou CUP,
Garmin GPI &amp; CSV, TomTom OV2 &amp; ITN, ONmove OMD/GHP, Garmin GPI &amp; CSV, TomTom OV2 &amp; ITN, ONmove OMD/GHP,
TwoNav (TRK, RTE, WPT), GPSDump WPT and geotagged JPEG TwoNav (TRK, RTE, WPT), GPSDump WPT, Velocitek VTK,
files.</li> Vakaros VKX, 70mai GPS logs and geotagged JPEG files.</li>
<li>Opens geo URIs (RFC 5870).</li> <li>Opens geo URIs (RFC 5870).</li>
<li>User-definable online maps (OpenStreetMap/Google tiles, WMTS, <li>User-definable online maps (OpenStreetMap/Google tiles, WMTS,
WMS, TMS, QuadTiles).</li> WMS, TMS, QuadTiles).</li>
@ -113,6 +113,9 @@
<mimetype>application/vnd.iho.s57-catalogue</mimetype> <mimetype>application/vnd.iho.s57-catalogue</mimetype>
<mimetype>application/vnd.gpsdump.wpt</mimetype> <mimetype>application/vnd.gpsdump.wpt</mimetype>
<mimetype>application/vnd.gpstuner.gmi</mimetype> <mimetype>application/vnd.gpstuner.gmi</mimetype>
<mimetype>application/vnd.70mai.txt</mimetype>
<mimetype>application/vnd.velocitek.vtk</mimetype>
<mimetype>application/vnd.vakaros.vkx</mimetype>
<mimetype>x-scheme-handler/geo</mimetype> <mimetype>x-scheme-handler/geo</mimetype>
</mimetypes> </mimetypes>
</component> </component>

View File

@ -16,4 +16,4 @@ Icon=gpxsee
Terminal=false Terminal=false
Type=Application Type=Application
Categories=Graphics;Viewer;Education;Geography;Maps;Sports;Qt Categories=Graphics;Viewer;Education;Geography;Maps;Sports;Qt
MimeType=x-scheme-handler/geo;application/gpx+xml;application/vnd.garmin.tcx+xml;application/vnd.ant.fit;application/vnd.google-earth.kml+xml;application/vnd.fai.igc;application/vnd.nmea.nmea;application/vnd.oziexplorer.plt;application/vnd.oziexplorer.rte;application/vnd.oziexplorer.wpt;application/vnd.groundspeak.loc+xml;application/vnd.sigma.slf+xml;application/geo+json;application/vnd.naviter.seeyou.cup;application/vnd.garmin.gpi;application/vnd.suunto.sml+xml;image/jpeg;text/csv;application/vnd.garmin.img;application/vnd.garmin.jnx;application/vnd.garmin.gmap+xml;image/vnd.maptech.kap;application/vnd.oziexplorer.map;application/vnd.mapbox.mbtiles;application/vnd.twonav.rmap;application/vnd.trekbuddy.tba;application/vnd.gpxsee.map+xml;application/x-tar;image/tiff;application/vnd.google-earth.kmz;application/vnd.alpinequest.aqm;application/vnd.cgtk.gemf;application/vnd.rmaps.sqlite;application/vnd.osmdroid.sqlite;application/vnd.mapsforge.map;application/vnd.tomtom.ov2;application/vnd.tomtom.itn;application/vnd.esri.wld;application/vnd.onmove.omd;application/vnd.onmove.ghp;application/vnd.memory-map.qct;application/vnd.twonav.trk;application/vnd.twonav.rte;application/vnd.twonav.wpt;application/vnd.orux.map+xml;application/vnd.iho.s57-data;application/vnd.iho.s57-catalogue;application/vnd.gpsdump.wpt;application/vnd.gpstuner.gmi MimeType=x-scheme-handler/geo;application/gpx+xml;application/vnd.garmin.tcx+xml;application/vnd.ant.fit;application/vnd.google-earth.kml+xml;application/vnd.fai.igc;application/vnd.nmea.nmea;application/vnd.oziexplorer.plt;application/vnd.oziexplorer.rte;application/vnd.oziexplorer.wpt;application/vnd.groundspeak.loc+xml;application/vnd.sigma.slf+xml;application/geo+json;application/vnd.naviter.seeyou.cup;application/vnd.garmin.gpi;application/vnd.suunto.sml+xml;image/jpeg;text/csv;application/vnd.garmin.img;application/vnd.garmin.jnx;application/vnd.garmin.gmap+xml;image/vnd.maptech.kap;application/vnd.oziexplorer.map;application/vnd.mapbox.mbtiles;application/vnd.twonav.rmap;application/vnd.trekbuddy.tba;application/vnd.gpxsee.map+xml;application/x-tar;image/tiff;application/vnd.google-earth.kmz;application/vnd.alpinequest.aqm;application/vnd.cgtk.gemf;application/vnd.rmaps.sqlite;application/vnd.osmdroid.sqlite;application/vnd.mapsforge.map;application/vnd.tomtom.ov2;application/vnd.tomtom.itn;application/vnd.esri.wld;application/vnd.onmove.omd;application/vnd.onmove.ghp;application/vnd.memory-map.qct;application/vnd.twonav.trk;application/vnd.twonav.rte;application/vnd.twonav.wpt;application/vnd.orux.map+xml;application/vnd.iho.s57-data;application/vnd.iho.s57-catalogue;application/vnd.gpsdump.wpt;application/vnd.gpstuner.gmi;application/vnd.70mai.txt;application/vnd.velocitek.vtk;application/vnd.vakaros.vkx

View File

@ -188,6 +188,33 @@
<glob pattern="*.wpt"/> <glob pattern="*.wpt"/>
</mime-type> </mime-type>
<mime-type type="application/vnd.70mai.txt">
<comment>70mai GPS Log File</comment>
<sub-class-of type="text/plain"/>
<generic-icon name="text/plain"/>
<magic>
<match type="string" offset="0" value="$V02"/>
</magic>
<glob pattern="*.txt"/>
</mime-type>
<mime-type type="application/vnd.velocitek.vtk">
<comment>Velocitek VTK File</comment>
<sub-class-of type="application/octet-stream"/>
<generic-icon name="application/octet-stream"/>
<glob pattern="*.vtk"/>
</mime-type>
<mime-type type="application/vnd.vakaros.vkx">
<comment>Vakaros VKX File</comment>
<sub-class-of type="application/octet-stream"/>
<generic-icon name="application/octet-stream"/>
<magic>
<match type="byte" offset="0" value="0xFF"/>
</magic>
<glob pattern="*.vkx"/>
</mime-type>
<!-- Maps --> <!-- Maps -->
<mime-type type="application/vnd.garmin.img"> <mime-type type="application/vnd.garmin.img">

View File

@ -736,6 +736,52 @@
<key>CFBundleTypeRole</key> <key>CFBundleTypeRole</key>
<string>Viewer</string> <string>Viewer</string>
</dict> </dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>txt</string>
</array>
<key>CFBundleTypeMIMETypes</key>
<array>
<string>application/vnd.70mai.txt</string>
</array>
<key>CFBundleTypeName</key>
<string>70mai GPS Log File</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>vtk</string>
</array>
<key>CFBundleTypeMIMETypes</key>
<array>
<string>application/vnd.velocitek.vtk</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>icons/vtk.icns</string>
<key>CFBundleTypeName</key>
<string>Velocitek VTK File</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>vkx</string>
</array>
<key>CFBundleTypeMIMETypes</key>
<array>
<string>application/vnd.vakaros.vkx</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>icons/vkx.icns</string>
<key>CFBundleTypeName</key>
<string>Vakaros VKX File</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
</array> </array>
<key>CFBundleURLTypes</key> <key>CFBundleURLTypes</key>
@ -1683,6 +1729,8 @@
<string>https://iho.int/uploads/user/pubs/standards/s-57/31Main.pdf</string> <string>https://iho.int/uploads/user/pubs/standards/s-57/31Main.pdf</string>
<key>UTTypeDescription</key> <key>UTTypeDescription</key>
<string>IHO S-57 Electronic Navigation Chart</string> <string>IHO S-57 Electronic Navigation Chart</string>
<key>UTTypeIconFile</key>
<string>icons/000.icns</string>
<key>UTTypeConformsTo</key> <key>UTTypeConformsTo</key>
<array> <array>
<string>public.data</string> <string>public.data</string>
@ -1704,6 +1752,8 @@
<string>https://iho.int/uploads/user/pubs/standards/s-57/20ApB1.pdf</string> <string>https://iho.int/uploads/user/pubs/standards/s-57/20ApB1.pdf</string>
<key>UTTypeDescription</key> <key>UTTypeDescription</key>
<string>IHO S-57 Electronic Navigation Catalogue</string> <string>IHO S-57 Electronic Navigation Catalogue</string>
<key>UTTypeIconFile</key>
<string>icons/031.icns</string>
<key>UTTypeConformsTo</key> <key>UTTypeConformsTo</key>
<array> <array>
<string>public.data</string> <string>public.data</string>
@ -1718,6 +1768,73 @@
<string>application/vnd.iho.s57-catalogue</string> <string>application/vnd.iho.s57-catalogue</string>
</dict> </dict>
</dict> </dict>
<dict>
<key>UTTypeIdentifier</key>
<string>com.70mai.txt</string>
<key>UTTypeReferenceURL</key>
<string>https://forum.mapillary.com/t/using-the-70mai-a810-dashcam-for-mapillary/9130/7?u=boris</string>
<key>UTTypeDescription</key>
<string>70mai GPS Log File</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>txt</string>
</array>
<key>public.mime-type</key>
<string>application/vnd.70mai.txt</string>
</dict>
</dict>
<dict>
<key>UTTypeIdentifier</key>
<string>com.velocitek.vtk</string>
<key>UTTypeReferenceURL</key>
<string>https://github.com/velocitek/vtk_protocol</string>
<key>UTTypeDescription</key>
<string>Velocitek VTK File</string>
<key>UTTypeIconFile</key>
<string>icons/vtk.icns</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>vtk</string>
</array>
<key>public.mime-type</key>
<string>application/vnd.velocitek.vtk</string>
</dict>
</dict>
<dict>
<key>UTTypeIdentifier</key>
<string>com.vakaros.vkx</string>
<key>UTTypeReferenceURL</key>
<string>https://github.com/vakaros/vkx</string>
<key>UTTypeDescription</key>
<string>Vakaros VKX File</string>
<key>UTTypeIconFile</key>
<string>icons/vkx.icns</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>vkx</string>
</array>
<key>public.mime-type</key>
<string>application/vnd.vakaros.vkx</string>
</dict>
</dict>
</array> </array>
<key>UTExportedTypeDeclarations</key> <key>UTExportedTypeDeclarations</key>

View File

@ -49,7 +49,7 @@ Unicode true
; The name of the installer ; The name of the installer
Name "GPXSee" Name "GPXSee"
; Program version ; Program version
!define VERSION "13.35" !define VERSION "13.39"
; The file to write ; The file to write
OutFile "GPXSee-${VERSION}_x64.exe" OutFile "GPXSee-${VERSION}_x64.exe"
@ -204,13 +204,15 @@ Section "GPXSee" SEC_APP
!insertmacro FILE_ASSOCIATION_ADD "gemf" "GEMF Map File" 26 !insertmacro FILE_ASSOCIATION_ADD "gemf" "GEMF Map File" 26
!insertmacro FILE_ASSOCIATION_ADD "000" "IHO S-57 Electronic Navigation Chart" 27 !insertmacro FILE_ASSOCIATION_ADD "000" "IHO S-57 Electronic Navigation Chart" 27
!insertmacro FILE_ASSOCIATION_ADD "031" "IHO S-57 Electronic Navigation Catalogue" 28 !insertmacro FILE_ASSOCIATION_ADD "031" "IHO S-57 Electronic Navigation Catalogue" 28
!insertmacro FILE_ASSOCIATION_ADD "kml" "Keyhole Markup Language" 29 !insertmacro FILE_ASSOCIATION_ADD "vtk" "Velocitek VTK File" 29
!insertmacro FILE_ASSOCIATION_ADD "kmz" "KML geographic compressed data" 29 !insertmacro FILE_ASSOCIATION_ADD "vkx" "Vakaros VKX File" 30
!insertmacro FILE_ASSOCIATION_ADD "fit" "Flexible and Interoperable Data Transfer" 30 !insertmacro FILE_ASSOCIATION_ADD "kml" "Keyhole Markup Language" 31
!insertmacro FILE_ASSOCIATION_ADD "igc" "Flight Recorder Data Format" 31 !insertmacro FILE_ASSOCIATION_ADD "kmz" "KML geographic compressed data" 31
!insertmacro FILE_ASSOCIATION_ADD "nmea" "NMEA 0183 Data" 32 !insertmacro FILE_ASSOCIATION_ADD "fit" "Flexible and Interoperable Data Transfer" 32
!insertmacro FILE_ASSOCIATION_ADD "plt" "OziExplorer Track File" 33 !insertmacro FILE_ASSOCIATION_ADD "igc" "Flight Recorder Data Format" 33
!insertmacro FILE_ASSOCIATION_ADD "rte" "OziExplorer Route File" 34 !insertmacro FILE_ASSOCIATION_ADD "nmea" "NMEA 0183 Data" 34
!insertmacro FILE_ASSOCIATION_ADD "plt" "OziExplorer Track File" 35
!insertmacro FILE_ASSOCIATION_ADD "rte" "OziExplorer Route File" 36
!insertmacro URI_ASSOCIATION_ADD "geo" !insertmacro URI_ASSOCIATION_ADD "geo"
@ -265,6 +267,9 @@ Section "GPXSee" SEC_APP
WriteRegStr HKCR ".gemf\OpenWithList" "GPXSee.exe" "" WriteRegStr HKCR ".gemf\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".000\OpenWithList" "GPXSee.exe" "" WriteRegStr HKCR ".000\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".031\OpenWithList" "GPXSee.exe" "" WriteRegStr HKCR ".031\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".txt\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".vtk\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".vkx\OpenWithList" "GPXSee.exe" ""
System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)' System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)'
@ -439,6 +444,8 @@ Section "Uninstall"
!insertmacro FILE_ASSOCIATION_REMOVE "gemf" !insertmacro FILE_ASSOCIATION_REMOVE "gemf"
!insertmacro FILE_ASSOCIATION_REMOVE "000" !insertmacro FILE_ASSOCIATION_REMOVE "000"
!insertmacro FILE_ASSOCIATION_REMOVE "031" !insertmacro FILE_ASSOCIATION_REMOVE "031"
!insertmacro FILE_ASSOCIATION_REMOVE "vtk"
!insertmacro FILE_ASSOCIATION_REMOVE "vkx"
!insertmacro URI_ASSOCIATION_REMOVE "geo" !insertmacro URI_ASSOCIATION_REMOVE "geo"
@ -492,6 +499,9 @@ Section "Uninstall"
DeleteRegValue HKCR ".gemf\OpenWithList" "GPXSee.exe" DeleteRegValue HKCR ".gemf\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".000\OpenWithList" "GPXSee.exe" DeleteRegValue HKCR ".000\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".031\OpenWithList" "GPXSee.exe" DeleteRegValue HKCR ".031\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".txt\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".vtk\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".vkx\OpenWithList" "GPXSee.exe"
DeleteRegKey HKCR "Applications\GPXSee.exe" DeleteRegKey HKCR "Applications\GPXSee.exe"
System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)' System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)'

View File

@ -73,9 +73,7 @@ App::App(int &argc, char **argv) : QApplication(argc, argv)
#if defined(Q_OS_WIN32) || defined(Q_OS_MAC) #if defined(Q_OS_WIN32) || defined(Q_OS_MAC)
QIcon::setThemeName(APP_NAME); QIcon::setThemeName(APP_NAME);
#endif // Q_OS_WIN32 || Q_OS_MAC #endif // Q_OS_WIN32 || Q_OS_MAC
#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)
QIcon::setFallbackThemeName(APP_NAME); QIcon::setFallbackThemeName(APP_NAME);
#endif // QT 5.12
_gui = new GUI(); _gui = new GUI();

View File

@ -25,15 +25,6 @@
#define IW(item) ((item)->boundingRect().width()) #define IW(item) ((item)->boundingRect().width())
#define IH(item) ((item)->boundingRect().height()) #define IH(item) ((item)->boundingRect().height())
static inline QPoint POS(QWheelEvent *e)
{
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
return e->pos();
#else // QT 5.15
return e->position().toPoint();
#endif // QT 5.15
}
static inline QPoint POS(QMouseEvent *e) static inline QPoint POS(QMouseEvent *e)
{ {
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
@ -393,7 +384,7 @@ void GraphView::wheelEvent(QWheelEvent *e)
return; return;
_angleDelta = _angleDelta % (15 * 8); _angleDelta = _angleDelta % (15 * 8);
QPointF pos = mapToScene(POS(e)); QPointF pos = mapToScene(e->position().toPoint());
QRectF gr(_grid->boundingRect()); QRectF gr(_grid->boundingRect());
QPointF r(pos.x() / gr.width(), pos.y() / gr.height()); QPointF r(pos.x() / gr.width(), pos.y() / gr.height());
@ -404,7 +395,8 @@ void GraphView::wheelEvent(QWheelEvent *e)
QPointF npos(mapFromScene(QPointF(r.x() * ngr.width(), QPointF npos(mapFromScene(QPointF(r.x() * ngr.width(),
r.y() * ngr.height()))); r.y() * ngr.height())));
QScrollBar *sb = horizontalScrollBar(); QScrollBar *sb = horizontalScrollBar();
sb->setSliderPosition(sb->sliderPosition() + npos.x() - POS(e).x()); sb->setSliderPosition(sb->sliderPosition() + npos.x()
- e->position().toPoint().x());
QGraphicsView::wheelEvent(e); QGraphicsView::wheelEvent(e);
} }

View File

@ -1193,11 +1193,13 @@ void GUI::loadData(const Data &data)
_time += track.time(); _time += track.time();
_movingTime += track.movingTime(); _movingTime += track.movingTime();
const QDateTime date = track.date().toTimeZone(_options.timeZone.zone()); const QDateTime date = track.date().toTimeZone(_options.timeZone.zone());
if (date.isValid()) {
if (_dateRange.first.isNull() || _dateRange.first > date) if (_dateRange.first.isNull() || _dateRange.first > date)
_dateRange.first = date; _dateRange.first = date;
if (_dateRange.second.isNull() || _dateRange.second < date) if (_dateRange.second.isNull() || _dateRange.second < date)
_dateRange.second = date; _dateRange.second = date;
} }
}
_trackCount += data.tracks().count(); _trackCount += data.tracks().count();
for (int i = 0; i < data.routes().count(); i++) for (int i = 0; i < data.routes().count(); i++)
@ -2498,12 +2500,8 @@ QGeoPositionInfoSource *GUI::positionSource(const Options &options)
{ {
QGeoPositionInfoSource *source; QGeoPositionInfoSource *source;
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
source = QGeoPositionInfoSource::createSource(options.plugin, this);
#else // QT 5.14
source = QGeoPositionInfoSource::createSource(options.plugin, source = QGeoPositionInfoSource::createSource(options.plugin,
options.pluginParams.value(options.plugin), this); options.pluginParams.value(options.plugin), this);
#endif // QT 5.14
if (source) if (source)
source->setPreferredPositioningMethods( source->setPreferredPositioningMethods(
QGeoPositionInfoSource::SatellitePositioningMethods); QGeoPositionInfoSource::SatellitePositioningMethods);

View File

@ -638,11 +638,7 @@ void MapView::wheelEvent(QWheelEvent *event)
return; return;
_wheelDelta = _wheelDelta % (15 * 8); _wheelDelta = _wheelDelta % (15 * 8);
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
zoom((delta > 0) ? 1 : -1, event->pos(), shift);
#else // QT 5.15
zoom((delta > 0) ? 1 : -1, event->position().toPoint(), shift); zoom((delta > 0) ? 1 : -1, event->position().toPoint(), shift);
#endif // QT 5.15
/* Do not call QGraphicsView::wheelEvent() here as this would shift the /* Do not call QGraphicsView::wheelEvent() here as this would shift the
view ! */ view ! */
@ -1258,7 +1254,7 @@ void MapView::drawHillShading(bool draw)
setMap(_map); setMap(_map);
} }
void MapView::selectLayers(Layers layers) void MapView::selectLayers(MapView::Layers layers)
{ {
_layers = layers; _layers = layers;

View File

@ -136,7 +136,7 @@ public slots:
void showMotionInfo(bool show); void showMotionInfo(bool show);
void useStyles(bool use); void useStyles(bool use);
void drawHillShading(bool draw); void drawHillShading(bool draw);
void selectLayers(Layers layers); void selectLayers(MapView::Layers layers);
private slots: private slots:
void updatePOI(); void updatePOI();

View File

@ -676,21 +676,17 @@ QWidget *OptionsDialog::createPositionPage()
_positionPlugin = new QComboBox(); _positionPlugin = new QComboBox();
_positionPlugin->addItems(plugins); _positionPlugin->addItems(plugins);
_positionPlugin->setCurrentIndex(_positionPlugin->findText(_options.plugin)); _positionPlugin->setCurrentIndex(_positionPlugin->findText(_options.plugin));
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
_pluginParameters = new PluginParameters(_positionPlugin->currentText(), _pluginParameters = new PluginParameters(_positionPlugin->currentText(),
_options.pluginParams); _options.pluginParams);
connect(_positionPlugin, &QComboBox::currentTextChanged, _pluginParameters, connect(_positionPlugin, &QComboBox::currentTextChanged, _pluginParameters,
&PluginParameters::setPlugin); &PluginParameters::setPlugin);
#endif // QT 5.14
QFormLayout *pluginLayout = new QFormLayout(); QFormLayout *pluginLayout = new QFormLayout();
pluginLayout->addRow(tr("Plugin:"), _positionPlugin); pluginLayout->addRow(tr("Plugin:"), _positionPlugin);
QVBoxLayout *sourceLayout = new QVBoxLayout(); QVBoxLayout *sourceLayout = new QVBoxLayout();
sourceLayout->addLayout(pluginLayout); sourceLayout->addLayout(pluginLayout);
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
sourceLayout->addWidget(_pluginParameters); sourceLayout->addWidget(_pluginParameters);
#endif // QT 5.14
sourceLayout->addStretch(); sourceLayout->addStretch();
QWidget *sourceTab = new QWidget(); QWidget *sourceTab = new QWidget();
@ -1009,9 +1005,7 @@ void OptionsDialog::accept()
_options.hillshadingZFactor = _hillshadingZFactor->value(); _options.hillshadingZFactor = _hillshadingZFactor->value();
_options.plugin = _positionPlugin->currentText(); _options.plugin = _positionPlugin->currentText();
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
_options.pluginParams = _pluginParameters->parameters(); _options.pluginParams = _pluginParameters->parameters();
#endif // QT 5.14
_options.useOpenGL = _useOpenGL->isChecked(); _options.useOpenGL = _useOpenGL->isChecked();
_options.enableHTTP2 = _enableHTTP2->isChecked(); _options.enableHTTP2 = _enableHTTP2->isChecked();

View File

@ -193,9 +193,7 @@ private:
QDoubleSpinBox *_hillshadingZFactor; QDoubleSpinBox *_hillshadingZFactor;
// Position // Position
QComboBox *_positionPlugin; QComboBox *_positionPlugin;
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
PluginParameters *_pluginParameters; PluginParameters *_pluginParameters;
#endif // QT 5.14
// System // System
QSpinBox *_pixmapCache; QSpinBox *_pixmapCache;
QSpinBox *_demCache; QSpinBox *_demCache;

View File

@ -10,13 +10,6 @@
#include "markeritem.h" #include "markeritem.h"
#include "pathitem.h" #include "pathitem.h"
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
#define INTERSECTS intersect
#else // QT 5.15
#define INTERSECTS intersects
#endif // QT 5.15
#define GEOGRAPHICAL_MILE 1855.3248 #define GEOGRAPHICAL_MILE 1855.3248
Units PathItem::_units = Metric; Units PathItem::_units = Metric;
@ -79,14 +72,14 @@ bool PathItem::addSegment(const Coordinates &c1, const Coordinates &c2)
QLineF l(QPointF(c1.lon(), c1.lat()), QPointF(c2.lon() + 360, QLineF l(QPointF(c1.lon(), c1.lat()), QPointF(c2.lon() + 360,
c2.lat())); c2.lat()));
QLineF dl(QPointF(180, -90), QPointF(180, 90)); QLineF dl(QPointF(180, -90), QPointF(180, 90));
l.INTERSECTS(dl, &p); l.intersects(dl, &p);
_painterPath.lineTo(_map->ll2xy(Coordinates(180, p.y()))); _painterPath.lineTo(_map->ll2xy(Coordinates(180, p.y())));
_painterPath.moveTo(_map->ll2xy(Coordinates(-180, p.y()))); _painterPath.moveTo(_map->ll2xy(Coordinates(-180, p.y())));
} else { } else {
QLineF l(QPointF(c1.lon(), c1.lat()), QPointF(c2.lon() - 360, QLineF l(QPointF(c1.lon(), c1.lat()), QPointF(c2.lon() - 360,
c2.lat())); c2.lat()));
QLineF dl(QPointF(-180, -90), QPointF(-180, 90)); QLineF dl(QPointF(-180, -90), QPointF(-180, 90));
l.INTERSECTS(dl, &p); l.intersects(dl, &p);
_painterPath.lineTo(_map->ll2xy(Coordinates(-180, p.y()))); _painterPath.lineTo(_map->ll2xy(Coordinates(-180, p.y())));
_painterPath.moveTo(_map->ll2xy(Coordinates(180, p.y()))); _painterPath.moveTo(_map->ll2xy(Coordinates(180, p.y())));
} }

View File

@ -9,9 +9,6 @@
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QFormLayout> #include <QFormLayout>
#include <QApplication> #include <QApplication>
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
#include <QDesktopWidget>
#endif // QT 5.15
#include "tooltip.h" #include "tooltip.h"
#include "thumbnail.h" #include "thumbnail.h"
#include "flowlayout.h" #include "flowlayout.h"
@ -184,11 +181,7 @@ bool PopupFrame::eventFilter(QObject *o, QEvent *ev)
void PopupFrame::place(const QPoint &pos, QWidget *w) void PopupFrame::place(const QPoint &pos, QWidget *w)
{ {
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
QRect screen = QApplication::desktop()->screenGeometry(w);
#else // QT 5.15
QRect screen = w->screen()->geometry(); QRect screen = w->screen()->geometry();
#endif // QT 5.15
QPoint p(pos.x() + 2, pos.y() + 16); QPoint p(pos.x() + 2, pos.y() + 16);
if (p.x() + width() > screen.x() + screen.width()) if (p.x() + width() > screen.x() + screen.width())

View File

@ -64,6 +64,7 @@ GraphItem *SpeedGraph::loadGraph(const Graph &graph, const Track &track,
if (primary) { if (primary) {
_avg.append(QPointF(track.distance(), gi->avg())); _avg.append(QPointF(track.distance(), gi->avg()));
_mavg.append(QPointF(track.distance(), gi->mavg())); _mavg.append(QPointF(track.distance(), gi->mavg()));
_max.append(QPointF(track.distance(), gi->max()));
} }
return gi; return gi;
@ -117,6 +118,16 @@ qreal SpeedGraph::avg() const
return (sum / w); return (sum / w);
} }
qreal SpeedGraph::max() const
{
qreal mv = 0;
for (int i = 0; i < _max.size(); i++)
mv = qMax(mv, _max.at(i).y());
return mv;
}
void SpeedGraph::clear() void SpeedGraph::clear()
{ {
qDeleteAll(_tracks); qDeleteAll(_tracks);
@ -124,6 +135,7 @@ void SpeedGraph::clear()
_avg.clear(); _avg.clear();
_mavg.clear(); _mavg.clear();
_max.clear();
GraphTab::clear(); GraphTab::clear();
} }

View File

@ -26,12 +26,13 @@ private:
GraphItem *loadGraph(const Graph &graph, const Track &track, GraphItem *loadGraph(const Graph &graph, const Track &track,
const QColor &color, bool primary); const QColor &color, bool primary);
qreal avg() const; qreal avg() const;
qreal max() const {return bounds().bottom();} qreal max() const;
void setYUnits(); void setYUnits();
void setInfo(); void setInfo();
QVector<QPointF> _avg; QVector<QPointF> _avg;
QVector<QPointF> _mavg; QVector<QPointF> _mavg;
QVector<QPointF> _max;
Units _units; Units _units;
TimeType _timeType; TimeType _timeType;

View File

@ -7,15 +7,18 @@ RFC 4180 parser with the following enchancements:
- allows LF line ends in addition to CRLF line ends - allows LF line ends in addition to CRLF line ends
*/ */
bool CSV::readEntry(QByteArrayList &list) bool CSV::readEntry(QByteArrayList &list, int limit)
{ {
int state = 0; int state = 0, len = 0;
char c; char c;
QByteArray field; QByteArray field;
list.clear(); list.clear();
while (_device->getChar(&c)) { while (_device->getChar(&c)) {
if (limit && ++len > limit)
return false;
switch (state) { switch (state) {
case 0: case 0:
if (c == '\r') if (c == '\r')

View File

@ -9,7 +9,7 @@ public:
CSV(QIODevice *device, char delimiter = ',') CSV(QIODevice *device, char delimiter = ',')
: _device(device), _delimiter(delimiter), _line(1) {} : _device(device), _delimiter(delimiter), _line(1) {}
bool readEntry(QByteArrayList &list); bool readEntry(QByteArrayList &list, int limit = 4096);
bool atEnd() const {return _device->atEnd();} bool atEnd() const {return _device->atEnd();}
int line() const {return _line;} int line() const {return _line;}

View File

@ -53,7 +53,7 @@ public:
bool intersects(const RectC &r) const bool intersects(const RectC &r) const
{return (right() >= r.left() && bottom() <= r.top() && left() <= r.right() {return (right() >= r.left() && bottom() <= r.top() && left() <= r.right()
&& top() >= r.bottom());} && top() >= r.bottom());}
bool contains(const Coordinates&c) const bool contains(const Coordinates &c) const
{return (c.lon() >= left() && c.lon() <= right() && c.lat() <= top() {return (c.lon() >= left() && c.lon() <= right() && c.lat() <= top()
&& c.lat() >= bottom());} && c.lat() >= bottom());}

View File

@ -115,7 +115,7 @@ public:
/// Count the data elements in this container. This is slow as no internal /// Count the data elements in this container. This is slow as no internal
/// counter is maintained. /// counter is maintained.
int Count(); int Count() const;
/// Iterator is not remove safe. /// Iterator is not remove safe.
@ -363,7 +363,7 @@ protected:
void* a_context) const; void* a_context) const;
void RemoveAllRec(Node* a_node); void RemoveAllRec(Node* a_node);
void Reset(); void Reset();
void CountRec(Node* a_node, int& a_count); void CountRec(Node* a_node, int& a_count) const;
/// Root of tree /// Root of tree
Node* m_root; Node* m_root;
@ -473,7 +473,7 @@ int RTREE_QUAL::Search(const ELEMTYPE a_min[NUMDIMS], const ELEMTYPE a_max[NUMDI
RTREE_TEMPLATE RTREE_TEMPLATE
int RTREE_QUAL::Count() int RTREE_QUAL::Count() const
{ {
int count = 0; int count = 0;
CountRec(m_root, count); CountRec(m_root, count);
@ -483,7 +483,7 @@ int RTREE_QUAL::Count()
RTREE_TEMPLATE RTREE_TEMPLATE
void RTREE_QUAL::CountRec(Node* a_node, int& a_count) void RTREE_QUAL::CountRec(Node* a_node, int& a_count) const
{ {
if (a_node->IsInternalNode()) { // not a leaf node if (a_node->IsInternalNode()) { // not a leaf node
for (int index = 0; index < a_node->m_count; ++index) for (int index = 0; index < a_node->m_count; ++index)

View File

@ -23,6 +23,9 @@
#include "onmoveparsers.h" #include "onmoveparsers.h"
#include "twonavparser.h" #include "twonavparser.h"
#include "gpsdumpparser.h" #include "gpsdumpparser.h"
#include "txtparser.h"
#include "vtkparser.h"
#include "vkxparser.h"
#include "data.h" #include "data.h"
@ -49,6 +52,9 @@ static OMDParser omd;
static GHPParser ghp; static GHPParser ghp;
static TwoNavParser twonav; static TwoNavParser twonav;
static GPSDumpParser gpsdump; static GPSDumpParser gpsdump;
static TXTParser txt;
static VTKParser vtk;
static VKXParser vkx;
static QMultiMap<QString, Parser*> parsers() static QMultiMap<QString, Parser*> parsers()
{ {
@ -82,6 +88,9 @@ static QMultiMap<QString, Parser*> parsers()
map.insert("rte", &twonav); map.insert("rte", &twonav);
map.insert("wpt", &twonav); map.insert("wpt", &twonav);
map.insert("wpt", &gpsdump); map.insert("wpt", &gpsdump);
map.insert("txt", &txt);
map.insert("vtk", &vtk);
map.insert("vkx", &vkx);
return map; return map;
} }
@ -241,6 +250,9 @@ QString Data::formats()
+ qApp->translate("Data", "SLF files") + " (*.slf);;" + qApp->translate("Data", "SLF files") + " (*.slf);;"
+ qApp->translate("Data", "SML files") + " (*.sml);;" + qApp->translate("Data", "SML files") + " (*.sml);;"
+ qApp->translate("Data", "TCX files") + " (*.tcx);;" + qApp->translate("Data", "TCX files") + " (*.tcx);;"
+ qApp->translate("Data", "70mai GPS log files") + " (*.txt);;"
+ qApp->translate("Data", "VKX files") + " (*.vkx);;"
+ qApp->translate("Data", "VTK files") + " (*.vtk);;"
+ qApp->translate("Data", "TwoNav files") + " (*.rte *.trk *.wpt);;" + qApp->translate("Data", "TwoNav files") + " (*.rte *.trk *.wpt);;"
+ qApp->translate("Data", "GPSDump files") + " (*.wpt);;" + qApp->translate("Data", "GPSDump files") + " (*.wpt);;"
+ qApp->translate("Data", "All files") + " (*)"; + qApp->translate("Data", "All files") + " (*)";

View File

@ -467,8 +467,7 @@ bool FITParser::parseHeader(CTX &ctx)
} }
bool FITParser::parse(QFile *file, QList<TrackData> &tracks, bool FITParser::parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QList<RouteData> &routes, QList<Area> &polygons, QVector<Waypoint> &waypoints)
QList<Area> &polygons, QVector<Waypoint> &waypoints)
{ {
Q_UNUSED(routes); Q_UNUSED(routes);
Q_UNUSED(polygons); Q_UNUSED(polygons);

View File

@ -541,7 +541,7 @@ void KMLParser::photoOverlay(const Ctx &ctx, QVector<Waypoint> &waypoints,
Waypoint w; Waypoint w;
QMap<QString, PolygonStyle> unused; QMap<QString, PolygonStyle> unused;
QMap<QString, LineStyle> unused2; QMap<QString, LineStyle> unused2;
static QRegularExpression re("\\$\\[[^\\]]+\\]"); static const QRegularExpression re("\\$\\[[^\\]]+\\]");
while (_reader.readNextStartElement()) { while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("name")) if (_reader.name() == QLatin1String("name"))

View File

@ -4,7 +4,6 @@
#include <QXmlStreamReader> #include <QXmlStreamReader>
#include "parser.h" #include "parser.h"
class TCXParser : public Parser class TCXParser : public Parser
{ {
public: public:

View File

@ -2,13 +2,6 @@
#include "map/gcs.h" #include "map/gcs.h"
#include "twonavparser.h" #include "twonavparser.h"
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
#define SKIP_EMPTY QString::SkipEmptyParts
#else // Qt 5.14
#define SKIP_EMPTY Qt::SkipEmptyParts
#endif
static double lon(const QString &str) static double lon(const QString &str)
{ {
QStringList l(str.split(QChar(0xBA))); QStringList l(str.split(QChar(0xBA)));
@ -123,7 +116,8 @@ bool TwoNavParser::parse(QFile *file, QList<TrackData> &tracks,
}} }}
break; break;
case 'T': case 'T':
{QStringList list(codec.toString(line).split(' ', SKIP_EMPTY)); {QStringList list(codec.toString(line).split(' ',
Qt::SkipEmptyParts));
if (list.size() < 4) { if (list.size() < 4) {
_errorString = "Parse error"; _errorString = "Parse error";
return false; return false;
@ -159,7 +153,8 @@ bool TwoNavParser::parse(QFile *file, QList<TrackData> &tracks,
tracks.last().last().append(t);} tracks.last().last().append(t);}
break; break;
case 'W': case 'W':
{QStringList list(codec.toString(line).split(' ', SKIP_EMPTY)); {QStringList list(codec.toString(line).split(' ',
Qt::SkipEmptyParts));
if (list.size() < 5) { if (list.size() < 5) {
_errorString = "Parse error"; _errorString = "Parse error";
return false; return false;

80
src/data/txtparser.cpp Normal file
View File

@ -0,0 +1,80 @@
#include <QTimeZone>
#include "common/csv.h"
#include "txtparser.h"
static Coordinates coordinates(const QByteArrayList &entry)
{
bool lonOk, latOk;
double lon = entry.at(3).toDouble(&lonOk);
double lat = entry.at(2).toDouble(&latOk);
return (lonOk && latOk) ? Coordinates(lon, lat) : Coordinates();
}
bool TXTParser::parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QList<Area> &polygons, QVector<Waypoint> &waypoints)
{
Q_UNUSED(routes);
Q_UNUSED(polygons);
Q_UNUSED(waypoints);
CSV csv(file);
QByteArrayList entry;
SegmentData *sg = 0;
_errorLine = 1;
_errorString.clear();
while (!csv.atEnd()) {
if (!csv.readEntry(entry)) {
_errorString = "CSV parse error";
_errorLine = csv.line() - 1;
return false;
}
if (entry.size() == 1) {
if (entry.at(0) == "$V02") {
tracks.append(TrackData(SegmentData()));
sg = &tracks.last().last();
} else {
_errorString = "Invalid track start marker";
_errorLine = csv.line() - 1;
return false;
}
} else {
if (!sg) {
_errorString = "Missing start marker";
_errorLine = csv.line() - 1;
return false;
}
if (entry.size() == 13 && entry.at(1) == "A") {
Coordinates c(coordinates(entry));
if (!c.isValid()) {
_errorString = "Invalid coordinates";
_errorLine = csv.line() - 1;
return false;
}
Trackpoint tp(c);
bool ok;
qulonglong ts = entry.at(0).toULongLong(&ok);
if (!ok) {
_errorString = "Invalid timestamp";
_errorLine = csv.line() - 1;
return false;
}
tp.setTimestamp(QDateTime::fromSecsSinceEpoch(ts,
QTimeZone::utc()));
uint speed = entry.at(5).toULong(&ok);
if (ok)
tp.setSpeed(speed * 0.01);
if (c != Coordinates(0, 0))
sg->append(tp);
}
}
}
return true;
}

18
src/data/txtparser.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef TXTPARSER_H
#define TXTPARSER_H
#include "parser.h"
class TXTParser : public Parser
{
bool parse(QFile *file, QList<TrackData> &tracks, QList<RouteData> &routes,
QList<Area> &polygons, QVector<Waypoint> &waypoints);
QString errorString() const {return _errorString;}
int errorLine() const {return _errorLine;}
private:
QString _errorString;
int _errorLine;
};
#endif // TXTPARSER_H

151
src/data/vkxparser.cpp Normal file
View File

@ -0,0 +1,151 @@
#include "vkxparser.h"
static bool readTrackPoint(QDataStream &stream, SegmentData &segment)
{
quint64 time;
qint32 lat, lon;
quint32 unused;
float speed, alt;
stream >> time >> lat >> lon;
if (stream.status() != QDataStream::Ok)
return false;
if (stream.readRawData((char*)&speed, 4) != 4)
return false;
stream >> unused;
if (stream.readRawData((char*)&alt, 4) != 4)
return false;
stream >> unused >> unused >> unused >> unused;
if (stream.status() != QDataStream::Ok)
return false;
Trackpoint t(Coordinates(lon / 1e7, lat / 1e7));
if (!t.coordinates().isValid())
return false;
t.setTimestamp(QDateTime::fromMSecsSinceEpoch(time));
t.setSpeed(speed);
t.setElevation(alt);
segment.append(t);
return true;
}
bool VKXParser::skip(QDataStream &stream, quint8 key, int len)
{
if (stream.skipRawData(len) != len) {
_errorString = "Invalid 0x" + QString::number(key, 16) + " row";
return false;
}
return true;
}
bool VKXParser::parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QList<Area> &polygons, QVector<Waypoint> &waypoints)
{
Q_UNUSED(routes);
Q_UNUSED(polygons);
Q_UNUSED(waypoints);
quint8 key;
quint64 hdr;
SegmentData segment;
QDataStream stream(file);
stream.setByteOrder(QDataStream::LittleEndian);
stream >> hdr;
if ((hdr & 0xFF) != 0xFF) {
_errorString = "Not a Vakaros VKX file";
return false;
}
while (stream.status() == QDataStream::Ok) {
stream >> key;
if (stream.status() != QDataStream::Ok)
break;
switch (key) {
case 0x01:
if (!skip(stream, key, 32))
return false;
break;
case 0x02:
if (!readTrackPoint(stream, segment)) {
_errorString = "Invalid 0x2 row";
return false;
}
break;
case 0x03:
if (!skip(stream, key, 20))
return false;
break;
case 0x04:
if (!skip(stream, key, 13))
return false;
break;
case 0x05:
if (!skip(stream, key, 17))
return false;
break;
case 0x06:
if (!skip(stream, key, 18))
return false;
break;
case 0x07:
if (!skip(stream, key, 12))
return false;
break;
case 0x08:
if (!skip(stream, key, 13))
return false;
break;
case 0x0A:
case 0x0B:
if (!skip(stream, key, 16))
return false;
break;
case 0x0C:
if (!skip(stream, key, 12))
return false;
break;
case 0x0E:
case 0x0F:
if (!skip(stream, key, 16))
return false;
break;
case 0x10:
if (!skip(stream, key, 12))
return false;
break;
case 0x20:
if (!skip(stream, key, 13))
return false;
break;
case 0x21:
if (!skip(stream, key, 52))
return false;
break;
case 0xFE:
if (!skip(stream, key, 2))
return false;
break;
case 0xFF:
if (!skip(stream, key, 7))
return false;
break;
default:
_errorString = "Unknown row key: 0x" + QString::number(key, 16);
return false;
}
}
if (stream.status() != QDataStream::ReadPastEnd) {
_errorString = "Unexpected EOF";
return false;
}
tracks.append(segment);
return true;
}

27
src/data/vkxparser.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef VKXPARSER_H
#define VKXPARSER_H
#include "parser.h"
class QDataStream;
class VKXParser : public Parser
{
public:
VKXParser()
{
static_assert(sizeof(float) == 4, "Invalid float size");
}
bool parse(QFile *file, QList<TrackData> &tracks, QList<RouteData> &routes,
QList<Area> &polygons, QVector<Waypoint> &waypoints);
QString errorString() const {return _errorString;}
int errorLine() const {return 0;}
private:
bool skip(QDataStream &stream, quint8 key, int len);
QString _errorString;
};
#endif // VKXPARSER_H

217
src/data/vtkparser.cpp Normal file
View File

@ -0,0 +1,217 @@
#include <QtEndian>
#include <QTimeZone>
#include "vtkparser.h"
#define TYPE(tag) (tag & 0x07)
#define FIELD(tag) (tag >> 3)
#define VARINT 0
#define I64 1
#define LEN 2
#define I32 5
struct CTX
{
CTX(const QByteArray &ba)
: bp(ba.constData()), be(bp + ba.size()), tag(0) {}
const char *bp;
const char *be;
quint32 tag;
};
static inline qint32 zigzag32decode(quint32 value)
{
return static_cast<qint32>((value >> 1u) ^ static_cast<quint32>(
-static_cast<qint32>(value & 1u)));
}
template<typename T>
static bool varint(CTX &ctx, T &val)
{
unsigned int shift = 0;
val = 0;
while (ctx.bp < ctx.be) {
val |= ((quint8)*ctx.bp & 0x7F) << shift;
shift += 7;
if (!((quint8)*ctx.bp++ & 0x80))
return true;
}
return false;
}
static bool length(CTX &ctx, qint32 &val)
{
if (TYPE(ctx.tag) != LEN)
return false;
if (!varint(ctx, val))
return false;
return (val >= 0);
}
static bool skip(CTX &ctx)
{
qint32 len = 0;
switch (TYPE(ctx.tag)) {
case VARINT:
return varint(ctx, len);
case I64:
len = 8;
break;
case LEN:
if (!varint(ctx, len) || len < 0)
return false;
break;
case I32:
len = 4;
break;
default:
return false;
}
if (ctx.bp + len > ctx.be)
return false;
ctx.bp += len;
return true;
}
static bool trackpoint(CTX &ctx, Trackpoint &t)
{
qint32 len, lon = 0xFFFFFFF, lat = 0xFFFFFFF;
quint32 val, seconds = 0, centiSeconds = 0, speed = 0;
if (!length(ctx, len))
return false;
const char *ee = ctx.bp + len;
if (ee > ctx.be)
return false;
while (ctx.bp < ee) {
if (!varint(ctx, ctx.tag))
return false;
switch (FIELD(ctx.tag)) {
case 1:
if (TYPE(ctx.tag) != VARINT)
return false;
if (!varint(ctx, seconds))
return false;
break;
case 2:
if (TYPE(ctx.tag) != VARINT)
return false;
if (!varint(ctx, centiSeconds))
return false;
break;
case 3:
if (TYPE(ctx.tag) != VARINT)
return false;
if (!varint(ctx, val))
return false;
lat = zigzag32decode(val);
break;
case 4:
if (TYPE(ctx.tag) != VARINT)
return false;
if (!varint(ctx, val))
return false;
lon = zigzag32decode(val);
break;
case 5:
if (TYPE(ctx.tag) != VARINT)
return false;
if (!varint(ctx, speed))
return false;
break;
default:
if (!skip(ctx))
return false;
}
}
t.setCoordinates(Coordinates(lon / 1e7, lat / 1e7));
t.setTimestamp(QDateTime::fromMSecsSinceEpoch(
((qint64)seconds * 1000) + ((qint64)centiSeconds * 10),
QTimeZone::utc()));
t.setSpeed(speed * 0.051444);
return (ctx.bp == ee);
}
static bool record(CTX &ctx, Trackpoint &t)
{
while (ctx.bp < ctx.be) {
if (!varint(ctx, ctx.tag))
return false;
switch (FIELD(ctx.tag)) {
case 1:
if (!trackpoint(ctx, t))
return false;
break;
default:
if (!skip(ctx))
return false;
}
}
return (ctx.bp == ctx.be);
}
bool VTKParser::parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QList<Area> &polygons, QVector<Waypoint> &waypoints)
{
Q_UNUSED(routes);
Q_UNUSED(polygons);
Q_UNUSED(waypoints);
qint64 len;
quint16 recordLen;
QByteArray ba;
SegmentData segment;
Trackpoint t;
_errorString = "";
while (true) {
if ((len = file->read((char*)&recordLen, sizeof(recordLen)))
!= sizeof(recordLen)) {
if (!len)
break;
else {
_errorString = "Error reading VTK record size";
return false;
}
}
recordLen = qFromLittleEndian(recordLen);
ba.resize(recordLen);
if (file->read(ba.data(), ba.size()) != ba.size()) {
_errorString = "Error reading VTK record";
return false;
}
CTX ctx(ba);
t.setCoordinates(Coordinates());
if (!record(ctx, t)) {
_errorString = "Invalid VTK record";
return false;
} else {
if (t.coordinates().isValid())
segment.append(t);
else if (!t.coordinates().isNull()) {
_errorString = "Invalid VTK record coordinates";
return false;
}
}
}
tracks.append(segment);
return true;
}

18
src/data/vtkparser.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef VTKPARSER_H
#define VTKPARSER_H
#include "parser.h"
class VTKParser : public Parser
{
public:
bool parse(QFile *file, QList<TrackData> &tracks, QList<RouteData> &routes,
QList<Area> &polygons, QVector<Waypoint> &waypoints);
QString errorString() const {return _errorString;}
int errorLine() const {return 0;}
private:
QString _errorString;
};
#endif // VTKPARSER_H

View File

@ -39,15 +39,12 @@ bool AtlasData::polyCb(MapEntry *map, void *context)
ctx->cacheLock.unlock(); ctx->cacheLock.unlock();
MapData *data = new MapData(map->path); MapData *data = new MapData(map->path);
data->polygons(ctx->rect, ctx->polygons); data->polys(ctx->rect, ctx->polygons, ctx->lines);
data->lines(ctx->rect, ctx->lines);
ctx->cacheLock.lock(); ctx->cacheLock.lock();
ctx->cache.insert(map->path, data); ctx->cache.insert(map->path, data);
} else { } else
cached->polygons(ctx->rect, ctx->polygons); cached->polys(ctx->rect, ctx->polygons, ctx->lines);
cached->lines(ctx->rect, ctx->lines);
}
ctx->cacheLock.unlock(); ctx->cacheLock.unlock();
map->lock.unlock(); map->lock.unlock();

View File

@ -10,18 +10,18 @@ namespace ENC {
typedef QCache<QString, MapData> MapCache; typedef QCache<QString, MapData> MapCache;
class AtlasData class AtlasData : public Data
{ {
public: public:
AtlasData(MapCache &cache, QMutex &cacheLock) AtlasData(MapCache &cache, QMutex &cacheLock)
: _cache(cache), _cacheLock(cacheLock) {} : _cache(cache), _cacheLock(cacheLock) {}
~AtlasData(); virtual ~AtlasData();
void addMap(const RectC &bounds, const QString &path); void addMap(const RectC &bounds, const QString &path);
void polys(const RectC &rect, QList<MapData::Poly> *polygons, virtual void polys(const RectC &rect, QList<MapData::Poly> *polygons,
QList<MapData::Line> *lines); QList<MapData::Line> *lines);
void points(const RectC &rect, QList<MapData::Point> *points); virtual void points(const RectC &rect, QList<MapData::Point> *points);
private: private:
struct MapEntry { struct MapEntry {

View File

@ -3,6 +3,7 @@
#define CATACH 8 #define CATACH 8
#define CATBUA 10 #define CATBUA 10
#define CATCOV 18
#define CATDIS 21 #define CATDIS 21
#define CATHAF 30 #define CATHAF 30
#define CATLMK 35 #define CATLMK 35

79
src/map/ENC/data.h Normal file
View File

@ -0,0 +1,79 @@
#ifndef ENC_DATA_H
#define ENC_DATA_H
#include "common/rectc.h"
#include "common/polygon.h"
namespace ENC {
class Data
{
public:
typedef QMap<uint, QByteArray> Attributes;
class Poly {
public:
Poly(uint type, const Polygon &path, const Attributes &attr, uint HUNI);
RectC bounds() const {return _path.boundingRect();}
const Polygon &path() const {return _path;}
uint type() const {return _type;}
const Attributes &attributes() const {return _attr;}
uint HUNI() const {return _HUNI;}
private:
uint _type;
Polygon _path;
Attributes _attr;
uint _HUNI;
};
class Line {
public:
Line(uint type, const QVector<Coordinates> &path, const Attributes &attr);
RectC bounds() const;
const QVector<Coordinates> &path() const {return _path;}
uint type() const {return _type;}
const QString &label() const {return _label;}
const Attributes &attributes() const {return _attr;}
private:
uint _type;
QVector<Coordinates> _path;
QString _label;
Attributes _attr;
};
class Point {
public:
Point(uint type, const Coordinates &c, const Attributes &attr,
uint HUNI, bool polygon = false);
Point(uint type, const Coordinates &s, const QString &label);
const Coordinates &pos() const {return _pos;}
uint type() const {return _type;}
const QString &label() const {return _label;}
const Attributes &attributes() const {return _attr;}
bool polygon() const {return _polygon;}
bool operator<(const Point &other) const
{return _id < other._id;}
private:
uint _type;
Coordinates _pos;
QString _label;
quint64 _id;
Attributes _attr;
bool _polygon;
};
virtual void polys(const RectC &rect, QList<Data::Poly> *polygons,
QList<Data::Line> *lines) = 0;
virtual void points(const RectC &rect, QList<Data::Point> *points) = 0;
};
}
#endif // ENC_DATA_H

View File

@ -1,3 +1,4 @@
#include <QtEndian>
#include <QFile> #include <QFile>
#include <QRegularExpression> #include <QRegularExpression>
#include "common/util.h" #include "common/util.h"
@ -5,13 +6,6 @@
using namespace ENC; using namespace ENC;
#define UINT16(x) \
(((quint16)*(const uchar*)(x)) \
| ((quint16)(*((const uchar*)(x) + 1)) << 8))
#define INT32(x) ((qint32)UINT32(x))
#define INT16(x) ((qint16)UINT16(x))
struct DR { struct DR {
char RecordLength[5]; char RecordLength[5];
char InterchangeLevel; char InterchangeLevel;
@ -29,18 +23,18 @@ struct DR {
}; };
const QVariant *ISO8211::Field::data(const QByteArray &name, int idx) const const QVariant *ISO8211::Field::data(quint32 name, int idx) const
{ {
const QVector<QVariant> &v = _data.at(idx); const QVector<QVariant> &v = _data.at(idx);
for (int i = 0; i < _subFields.size(); i++) for (int i = 0; i < _subFields->size(); i++)
if (_subFields.at(i) == name) if (_subFields->at(i) == name)
return &v.at(i); return &v.at(i);
return 0; return 0;
} }
bool ISO8211::Field::subfield(const char *name, int *val, int idx) const bool ISO8211::Field::subfield(quint32 name, int *val, int idx) const
{ {
bool ok; bool ok;
@ -52,7 +46,7 @@ bool ISO8211::Field::subfield(const char *name, int *val, int idx) const
return ok; return ok;
} }
bool ISO8211::Field::subfield(const char *name, uint *val, int idx) const bool ISO8211::Field::subfield(quint32 name, uint *val, int idx) const
{ {
bool ok; bool ok;
@ -64,7 +58,7 @@ bool ISO8211::Field::subfield(const char *name, uint *val, int idx) const
return ok; return ok;
} }
bool ISO8211::Field::subfield(const char *name, QByteArray *val, int idx) const bool ISO8211::Field::subfield(quint32 name, QByteArray *val, int idx) const
{ {
const QVariant *v = data(name, idx); const QVariant *v = data(name, idx);
if (!v) if (!v)
@ -101,6 +95,7 @@ int ISO8211::readDR(QVector<FieldDefinition> &fields)
DR ddr; DR ddr;
QByteArray fieldLen, fieldPos; QByteArray fieldLen, fieldPos;
int len, lenSize, posSize, tagSize, offset; int len, lenSize, posSize, tagSize, offset;
char tag[4];
static_assert(sizeof(ddr) == 24, "Invalid DR alignment"); static_assert(sizeof(ddr) == 24, "Invalid DR alignment");
if (_file.read((char*)&ddr, sizeof(ddr)) != sizeof(ddr)) if (_file.read((char*)&ddr, sizeof(ddr)) != sizeof(ddr))
@ -115,20 +110,19 @@ int ISO8211::readDR(QVector<FieldDefinition> &fields)
if (len < 0 || offset < 0 || lenSize < 0 || posSize < 0 || tagSize < 0) if (len < 0 || offset < 0 || lenSize < 0 || posSize < 0 || tagSize < 0)
return -1; return -1;
fields.resize((offset - 1 - sizeof(DR)) / (lenSize + posSize + tagSize)); fields.resize((offset - 1 - sizeof(ddr)) / (lenSize + posSize + tagSize));
fieldLen.resize(lenSize); fieldLen.resize(lenSize);
fieldPos.resize(posSize); fieldPos.resize(posSize);
for (int i = 0; i < fields.size(); i++) { for (int i = 0; i < fields.size(); i++) {
FieldDefinition &r = fields[i]; FieldDefinition &r = fields[i];
r.tag.resize(tagSize); if (_file.read(tag, sizeof(tag)) != tagSize
if (_file.read(r.tag.data(), tagSize) != tagSize
|| _file.read(fieldLen.data(), lenSize) != lenSize || _file.read(fieldLen.data(), lenSize) != lenSize
|| _file.read(fieldPos.data(), posSize) != posSize) || _file.read(fieldPos.data(), posSize) != posSize)
return -1; return -1;
r.tag = qFromLittleEndian<quint32>(tag);
r.pos = offset + Util::str2int(fieldPos.constData(), posSize); r.pos = offset + Util::str2int(fieldPos.constData(), posSize);
r.size = Util::str2int(fieldLen.constData(), lenSize); r.size = Util::str2int(fieldLen.constData(), lenSize);
@ -141,13 +135,13 @@ int ISO8211::readDR(QVector<FieldDefinition> &fields)
bool ISO8211::readDDA(const FieldDefinition &def, SubFields &fields) bool ISO8211::readDDA(const FieldDefinition &def, SubFields &fields)
{ {
static QRegularExpression re("(\\d*)(\\w+)\\(*(\\d*)\\)*"); static const QRegularExpression re(
QByteArray ba; "([0-9]*)(A|I|R|B|b11|b12|b14|b21|b22|b24)\\(*([0-9]*)\\)*");
QByteArray ba(def.size, Qt::Initialization::Uninitialized);
bool repeat = false; bool repeat = false;
QVector<SubFieldDefinition> defs; QVector<SubFieldDefinition> defs;
QVector<QByteArray> defTags; QVector<quint32> defTags;
ba.resize(def.size);
if (!(_file.seek(def.pos) && _file.read(ba.data(), ba.size()) == ba.size())) if (!(_file.seek(def.pos) && _file.read(ba.data(), ba.size()) == ba.size()))
return false; return false;
@ -156,9 +150,9 @@ bool ISO8211::readDDA(const FieldDefinition &def, SubFields &fields)
repeat = true; repeat = true;
list[1].remove(0, 1); list[1].remove(0, 1);
} }
QList<QByteArray> tags(list.at(1).split('!'));
if (list.size() > 2) { if (list.size() > 2) {
QList<QByteArray> tags(list.at(1).split('!'));
QRegularExpressionMatchIterator it = re.globalMatch(list.at(2)); QRegularExpressionMatchIterator it = re.globalMatch(list.at(2));
int tag = 0; int tag = 0;
@ -188,11 +182,17 @@ bool ISO8211::readDDA(const FieldDefinition &def, SubFields &fields)
SubFieldDefinition sfd(fieldType(typeStr, size)); SubFieldDefinition sfd(fieldType(typeStr, size));
if (sfd.type() == Unknown) if (sfd.type() == Unknown)
return false; return false;
if (tag >= tags.size())
return false;
defs[tag] = sfd; defs[tag] = sfd;
defTags[tag] = tags.at(tag); defTags[tag] = (tags.at(tag).length() == 4)
? qFromLittleEndian<quint32>(tags.at(tag).constData()) : 0;
tag++; tag++;
} }
} }
if (tag != tags.size())
return false;
} }
fields = SubFields(defTags, defs, repeat); fields = SubFields(defTags, defs, repeat);
@ -218,8 +218,10 @@ bool ISO8211::readDDR()
for (int i = 0; i < fields.size(); i++) { for (int i = 0; i < fields.size(); i++) {
SubFields def; SubFields def;
if (!readDDA(fields.at(i), def)) { if (!readDDA(fields.at(i), def)) {
QByteArray tag(sizeof(quint32), Qt::Initialization::Uninitialized);
qToLittleEndian<quint32>(fields.at(i).tag, tag.data());
_errorString = QString("Error reading %1 DDA field") _errorString = QString("Error reading %1 DDA field")
.arg(QString(fields.at(i).tag)); .arg(QString(tag));
return false; return false;
} }
_map.insert(fields.at(i).tag, def); _map.insert(fields.at(i).tag, def);
@ -236,9 +238,8 @@ bool ISO8211::readDDR()
bool ISO8211::readUDA(quint64 pos, const FieldDefinition &def, bool ISO8211::readUDA(quint64 pos, const FieldDefinition &def,
const QVector<SubFieldDefinition> &fields, bool repeat, Data &data) const QVector<SubFieldDefinition> &fields, bool repeat, Data &data)
{ {
QByteArray ba; QByteArray ba(def.size, Qt::Initialization::Uninitialized);
ba.resize(def.size);
if (!(_file.seek(pos + def.pos) if (!(_file.seek(pos + def.pos)
&& _file.read(ba.data(), ba.size()) == ba.size())) && _file.read(ba.data(), ba.size()) == ba.size()))
return false; return false;
@ -248,8 +249,7 @@ bool ISO8211::readUDA(quint64 pos, const FieldDefinition &def,
const char *ep = ba.constData() + ba.size() - 1; const char *ep = ba.constData() + ba.size() - 1;
do { do {
QVector<QVariant> row; QVector<QVariant> row(fields.size());
row.resize(fields.size());
for (int i = 0; i < fields.size(); i++) { for (int i = 0; i < fields.size(); i++) {
const SubFieldDefinition &f = fields.at(i); const SubFieldDefinition &f = fields.at(i);
@ -273,11 +273,11 @@ bool ISO8211::readUDA(quint64 pos, const FieldDefinition &def,
dp++; dp++;
break; break;
case S16: case S16:
row[i] = QVariant(INT16(dp)); row[i] = QVariant(qFromLittleEndian<qint16>(dp));
dp += 2; dp += 2;
break; break;
case S32: case S32:
row[i] = QVariant(INT32(dp)); row[i] = QVariant(qFromLittleEndian<qint32>(dp));
dp += 4; dp += 4;
break; break;
case U8: case U8:
@ -285,11 +285,11 @@ bool ISO8211::readUDA(quint64 pos, const FieldDefinition &def,
dp++; dp++;
break; break;
case U16: case U16:
row[i] = QVariant(UINT16(dp)); row[i] = QVariant(qFromLittleEndian<quint16>(dp));
dp += 2; dp += 2;
break; break;
case U32: case U32:
row[i] = QVariant(UINT32(dp)); row[i] = QVariant(qFromLittleEndian<quint32>(dp));
dp += 4; dp += 4;
break; break;
default: default:
@ -325,13 +325,16 @@ bool ISO8211::readRecord(Record &record)
FieldsMap::const_iterator it(_map.find(def.tag)); FieldsMap::const_iterator it(_map.find(def.tag));
if (it == _map.constEnd()) { if (it == _map.constEnd()) {
_errorString = QString("%1: unknown record").arg(QString(def.tag)); QByteArray tag(sizeof(quint32), Qt::Initialization::Uninitialized);
qToLittleEndian<quint32>(def.tag, tag.data());
_errorString = QString("%1: unknown record").arg(QString(tag));
return false; return false;
} }
if (!readUDA(pos, def, it->defs(), it->repeat(), data)) { if (!readUDA(pos, def, it->defs(), it->repeat(), data)) {
_errorString = QString("Error reading %1 record") QByteArray tag(sizeof(quint32), Qt::Initialization::Uninitialized);
.arg(QString(def.tag)); qToLittleEndian<quint32>(def.tag, tag.data());
_errorString = QString("Error reading %1 record").arg(QString(tag));
return false; return false;
} }
@ -341,8 +344,7 @@ bool ISO8211::readRecord(Record &record)
return true; return true;
} }
const ISO8211::Field *ISO8211::field(const Record &record, quint32 name)
const ISO8211::Field *ISO8211::field(const Record &record, const QByteArray &name)
{ {
for (int i = 0; i < record.size(); i++) for (int i = 0; i < record.size(); i++)
if (record.at(i).tag() == name) if (record.at(i).tag() == name)

View File

@ -4,13 +4,6 @@
#include <QFile> #include <QFile>
#include <QByteArray> #include <QByteArray>
#include <QVariant> #include <QVariant>
#include <QDebug>
#define UINT32(x) \
(((quint32)*(const uchar*)(x)) \
| ((quint32)(*((const uchar*)(x) + 1)) << 8) \
| ((quint32)(*((const uchar*)(x) + 2)) << 16) \
| ((quint32)(*((const uchar*)(x) + 3)) << 24))
namespace ENC { namespace ENC {
@ -22,23 +15,22 @@ public:
class Field class Field
{ {
public: public:
Field() {} Field() : _subFields(0) {}
Field(const QByteArray &tag, const QVector<QByteArray> &subFields, Field(quint32 tag, const QVector<quint32> &subFields, const Data &data)
const Data &data) : _tag(tag), _subFields(subFields), _data(data) {} : _tag(tag), _subFields(&subFields), _data(data) {}
const QByteArray &tag() const {return _tag;} quint32 tag() const {return _tag;}
const QVector<QByteArray> &subFields() const {return _subFields;}
const Data &data() const {return _data;} const Data &data() const {return _data;}
bool subfield(const char *name, int *val, int idx = 0) const; bool subfield(quint32 name, int *val, int idx = 0) const;
bool subfield(const char *name, uint *val, int idx = 0) const; bool subfield(quint32 name, uint *val, int idx = 0) const;
bool subfield(const char *name, QByteArray *val, int idx = 0) const; bool subfield(quint32 name, QByteArray *val, int idx = 0) const;
private: private:
const QVariant *data(const QByteArray &name, int idx = 0) const; const QVariant *data(quint32 name, int idx = 0) const;
QByteArray _tag; quint32 _tag;
QVector<QByteArray> _subFields; const QVector<quint32> *_subFields;
Data _data; Data _data;
}; };
@ -50,14 +42,21 @@ public:
const QString &errorString() const {return _errorString;} const QString &errorString() const {return _errorString;}
static const Field *field(const Record &record, const QByteArray &name); static const Field *field(const Record &record, quint32 name);
static constexpr quint32 NAME(const char str[4])
{
return static_cast<quint32>(str[0])
+ (static_cast<quint32>(str[1]) << 8)
+ (static_cast<quint32>(str[2]) << 16)
+ (static_cast<quint32>(str[3]) << 24);
}
private: private:
enum FieldType {Unknown, String, Array, S8, S16, S32, U8, U16, U32}; enum FieldType {Unknown, String, Array, S8, S16, S32, U8, U16, U32};
struct FieldDefinition struct FieldDefinition
{ {
QByteArray tag; quint32 tag;
int pos; int pos;
int size; int size;
}; };
@ -81,22 +80,22 @@ private:
{ {
public: public:
SubFields() : _repeat(false) {} SubFields() : _repeat(false) {}
SubFields(const QVector<QByteArray> &tags, SubFields(const QVector<quint32> &tags,
const QVector<SubFieldDefinition> &defs, bool repeat) const QVector<SubFieldDefinition> &defs, bool repeat)
: _tags(tags), _defs(defs), _repeat(repeat) {} : _tags(tags), _defs(defs), _repeat(repeat) {}
const QVector<QByteArray> &tags() const {return _tags;} const QVector<quint32> &tags() const {return _tags;}
const QVector<SubFieldDefinition> &defs() const {return _defs;} const QVector<SubFieldDefinition> &defs() const {return _defs;}
bool repeat() const {return _repeat;} bool repeat() const {return _repeat;}
private: private:
QVector<QByteArray> _tags; QVector<quint32> _tags;
QVector<SubFieldDefinition> _defs; QVector<SubFieldDefinition> _defs;
bool _repeat; bool _repeat;
}; };
typedef QMap<QByteArray, SubFields> FieldsMap; typedef QMap<quint32, SubFields> FieldsMap;
static SubFieldDefinition fieldType(const QString &str, int cnt); static SubFieldDefinition fieldType(const QString &str, int cnt);
@ -110,14 +109,6 @@ private:
QString _errorString; QString _errorString;
}; };
#ifndef QT_NO_DEBUG
inline QDebug operator<<(QDebug dbg, const ISO8211::Field &field)
{
dbg.nospace() << "Field(" << field.tag() << ", " << field.subFields() << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG
} }
#endif // ENC_ISO8211_H #endif // ENC_ISO8211_H

View File

@ -1,3 +1,4 @@
#include <QtEndian>
#include "GUI/units.h" #include "GUI/units.h"
#include "objects.h" #include "objects.h"
#include "attributes.h" #include "attributes.h"
@ -14,6 +15,19 @@ using namespace ENC;
#define PRIM_L 2 #define PRIM_L 2
#define PRIM_A 3 #define PRIM_A 3
constexpr quint32 RCID = ISO8211::NAME("RCID");
constexpr quint32 SG2D = ISO8211::NAME("SG2D");
constexpr quint32 SG3D = ISO8211::NAME("SG3D");
constexpr quint32 FSPT = ISO8211::NAME("FSPT");
constexpr quint32 VRPT = ISO8211::NAME("VRPT");
constexpr quint32 ATTF = ISO8211::NAME("ATTF");
constexpr quint32 VRID = ISO8211::NAME("VRID");
constexpr quint32 FRID = ISO8211::NAME("FRID");
constexpr quint32 DSPM = ISO8211::NAME("DSPM");
constexpr quint32 COMF = ISO8211::NAME("COMF");
constexpr quint32 SOMF = ISO8211::NAME("SOMF");
constexpr quint32 HUNI = ISO8211::NAME("HUNI");
static QMap<uint,uint> orderMapInit() static QMap<uint,uint> orderMapInit()
{ {
QMap<uint,uint> map; QMap<uint,uint> map;
@ -90,20 +104,20 @@ static uint order(uint type)
return (it == orderMap.constEnd()) ? (type>>16) + 512 : it.value(); return (it == orderMap.constEnd()) ? (type>>16) + 512 : it.value();
} }
static void warning(const ISO8211::Field &FRID, uint PRIM) static void warning(const ISO8211::Field &frid, uint prim)
{ {
uint RCID = 0xFFFFFFFF; uint rcid = 0xFFFFFFFF;
FRID.subfield("RCID", &RCID); frid.subfield(RCID, &rcid);
switch (PRIM) { switch (prim) {
case PRIM_P: case PRIM_P:
qWarning("%u: invalid point feature", RCID); qWarning("%u: invalid point feature", rcid);
break; break;
case PRIM_L: case PRIM_L:
qWarning("%u: invalid line feature", RCID); qWarning("%u: invalid line feature", rcid);
break; break;
case PRIM_A: case PRIM_A:
qWarning("%u: invalid area feature", RCID); qWarning("%u: invalid area feature", rcid);
break; break;
} }
} }
@ -132,7 +146,7 @@ static bool parseNAME(const ISO8211::Field *f, quint8 *type, quint32 *id,
return false; return false;
*type = (quint8)(*ba.constData()); *type = (quint8)(*ba.constData());
*id = UINT32(ba.constData() + 1); *id = qFromLittleEndian<quint32>(ba.constData() + 1);
return true; return true;
} }
@ -141,9 +155,9 @@ static const ISO8211::Field *SGXD(const ISO8211::Record &r)
{ {
const ISO8211::Field *f; const ISO8211::Field *f;
if ((f = ISO8211::field(r, "SG2D"))) if ((f = ISO8211::field(r, SG2D)))
return f; return f;
else if ((f = ISO8211::field(r, "SG3D"))) else if ((f = ISO8211::field(r, SG3D)))
return f; return f;
else else
return 0; return 0;
@ -212,12 +226,12 @@ static bool linePointCb(const MapData::Line *line, void *context)
return true; return true;
} }
static Coordinates coordinates(int x, int y, uint COMF) static Coordinates coordinates(int x, int y, uint comf)
{ {
return Coordinates(x / (double)COMF, y / (double)COMF); return Coordinates(x / (double)comf, y / (double)comf);
} }
static Coordinates point(const ISO8211::Record &r, uint COMF) static Coordinates point(const ISO8211::Record &r, uint comf)
{ {
const ISO8211::Field *f = SGXD(r); const ISO8211::Field *f = SGXD(r);
if (!f) if (!f)
@ -226,7 +240,7 @@ static Coordinates point(const ISO8211::Record &r, uint COMF)
int y = f->data().at(0).at(0).toInt(); int y = f->data().at(0).at(0).toInt();
int x = f->data().at(0).at(1).toInt(); int x = f->data().at(0).at(1).toInt();
return coordinates(x, y, COMF); return coordinates(x, y, comf);
} }
static uint depthLevel(double minDepth) static uint depthLevel(double minDepth)
@ -362,6 +376,8 @@ MapData::Point::Point(uint type, const Coordinates &c, const Attributes &attr,
subtype = CATACH; subtype = CATACH;
else if (type == I_ACHARE) else if (type == I_ACHARE)
subtype = I_CATACH; subtype = I_CATACH;
else if (type == MARKUL)
subtype = CATMFA;
QList<QByteArray> list(_attr.value(subtype).split(',')); QList<QByteArray> list(_attr.value(subtype).split(','));
std::sort(list.begin(), list.end()); std::sort(list.begin(), list.end());
@ -423,6 +439,8 @@ MapData::Poly::Poly(uint type, const Polygon &path, const Attributes &attr,
subtype = CATMFA; subtype = CATMFA;
else if (type == I_BERTHS) else if (type == I_BERTHS)
subtype = I_CATBRT; subtype = I_CATBRT;
else if (type == M_COVR)
subtype = CATCOV;
switch (type) { switch (type) {
case DEPARE: case DEPARE:
@ -473,10 +491,10 @@ RectC MapData::Line::bounds() const
} }
QVector<MapData::Sounding> MapData::soundings(const ISO8211::Record &r, QVector<MapData::Sounding> MapData::soundings(const ISO8211::Record &r,
uint COMF, uint SOMF) uint comf, uint somf)
{ {
QVector<Sounding> s; QVector<Sounding> s;
const ISO8211::Field *f = ISO8211::field(r, "SG3D"); const ISO8211::Field *f = ISO8211::field(r, SG3D);
if (!f) if (!f)
return QVector<Sounding>(); return QVector<Sounding>();
@ -485,24 +503,24 @@ QVector<MapData::Sounding> MapData::soundings(const ISO8211::Record &r,
int y = f->data().at(i).at(0).toInt(); int y = f->data().at(i).at(0).toInt();
int x = f->data().at(i).at(1).toInt(); int x = f->data().at(i).at(1).toInt();
int z = f->data().at(i).at(2).toInt(); int z = f->data().at(i).at(2).toInt();
s.append(Sounding(coordinates(x, y, COMF), z / (double)SOMF)); s.append(Sounding(coordinates(x, y, comf), z / (double)somf));
} }
return s; return s;
} }
QVector<MapData::Sounding> MapData::soundingGeometry(const ISO8211::Record &r, QVector<MapData::Sounding> MapData::soundingGeometry(const ISO8211::Record &r,
const RecordMap &vi, const RecordMap &vc, uint COMF, uint SOMF) const RecordMap &vi, const RecordMap &vc, uint comf, uint somf)
{ {
quint8 type; quint8 type;
quint32 id; quint32 id;
RecordMapIterator it; RecordMapIterator it;
const ISO8211::Field *FSPT = ISO8211::field(r, "FSPT"); const ISO8211::Field *fspt = ISO8211::field(r, FSPT);
if (!FSPT || FSPT->data().at(0).size() != 4) if (!fspt || fspt->data().at(0).size() != 4)
return QVector<Sounding>(); return QVector<Sounding>();
if (!parseNAME(FSPT, &type, &id)) if (!parseNAME(fspt, &type, &id))
return QVector<Sounding>(); return QVector<Sounding>();
if (type == RCNM_VI) { if (type == RCNM_VI) {
@ -516,21 +534,21 @@ QVector<MapData::Sounding> MapData::soundingGeometry(const ISO8211::Record &r,
} else } else
return QVector<Sounding>(); return QVector<Sounding>();
return soundings(it.value(), COMF, SOMF); return soundings(it.value(), comf, somf);
} }
Coordinates MapData::pointGeometry(const ISO8211::Record &r, Coordinates MapData::pointGeometry(const ISO8211::Record &r,
const RecordMap &vi, const RecordMap &vc, uint COMF) const RecordMap &vi, const RecordMap &vc, uint comf)
{ {
quint8 type; quint8 type;
quint32 id; quint32 id;
RecordMapIterator it; RecordMapIterator it;
const ISO8211::Field *FSPT = ISO8211::field(r, "FSPT"); const ISO8211::Field *fspt = ISO8211::field(r, FSPT);
if (!FSPT || FSPT->data().at(0).size() != 4) if (!fspt || fspt->data().at(0).size() != 4)
return Coordinates(); return Coordinates();
if (!parseNAME(FSPT, &type, &id)) if (!parseNAME(fspt, &type, &id))
return Coordinates(); return Coordinates();
if (type == RCNM_VI) { if (type == RCNM_VI) {
@ -544,55 +562,55 @@ Coordinates MapData::pointGeometry(const ISO8211::Record &r,
} else } else
return Coordinates(); return Coordinates();
return point(it.value(), COMF); return point(it.value(), comf);
} }
QVector<Coordinates> MapData::lineGeometry(const ISO8211::Record &r, QVector<Coordinates> MapData::lineGeometry(const ISO8211::Record &r,
const RecordMap &vc, const RecordMap &ve, uint COMF) const RecordMap &vc, const RecordMap &ve, uint comf)
{ {
QVector<Coordinates> path; QVector<Coordinates> path;
Coordinates c[2]; Coordinates c[2];
uint ORNT; uint ornt;
quint8 type; quint8 type;
quint32 id; quint32 id;
const ISO8211::Field *FSPT = ISO8211::field(r, "FSPT"); const ISO8211::Field *fspt = ISO8211::field(r, FSPT);
if (!FSPT || FSPT->data().at(0).size() != 4) if (!fspt || fspt->data().at(0).size() != 4)
return QVector<Coordinates>(); return QVector<Coordinates>();
for (int i = 0; i < FSPT->data().size(); i++) { for (int i = 0; i < fspt->data().size(); i++) {
if (!parseNAME(FSPT, &type, &id, i) || type != RCNM_VE) if (!parseNAME(fspt, &type, &id, i) || type != RCNM_VE)
return QVector<Coordinates>(); return QVector<Coordinates>();
ORNT = FSPT->data().at(i).at(1).toUInt(); ornt = fspt->data().at(i).at(1).toUInt();
RecordMapIterator it = ve.find(id); RecordMapIterator it = ve.find(id);
if (it == ve.constEnd()) if (it == ve.constEnd())
return QVector<Coordinates>(); return QVector<Coordinates>();
const ISO8211::Record &FRID = it.value(); const ISO8211::Record &frid = it.value();
const ISO8211::Field *VRPT = ISO8211::field(FRID, "VRPT"); const ISO8211::Field *vrpt = ISO8211::field(frid, VRPT);
if (!VRPT || VRPT->data().size() != 2) if (!vrpt || vrpt->data().size() != 2)
return QVector<Coordinates>(); return QVector<Coordinates>();
for (int j = 0; j < 2; j++) { for (int j = 0; j < 2; j++) {
if (!parseNAME(VRPT, &type, &id, j) || type != RCNM_VC) if (!parseNAME(vrpt, &type, &id, j) || type != RCNM_VC)
return QVector<Coordinates>(); return QVector<Coordinates>();
RecordMapIterator jt = vc.find(id); RecordMapIterator jt = vc.find(id);
if (jt == vc.constEnd()) if (jt == vc.constEnd())
return QVector<Coordinates>(); return QVector<Coordinates>();
c[j] = point(jt.value(), COMF); c[j] = point(jt.value(), comf);
if (c[j].isNull()) if (c[j].isNull())
return QVector<Coordinates>(); return QVector<Coordinates>();
} }
const ISO8211::Field *vertexes = SGXD(FRID); const ISO8211::Field *vertexes = SGXD(frid);
if (ORNT == 2) { if (ornt == 2) {
path.append(c[1]); path.append(c[1]);
if (vertexes) { if (vertexes) {
for (int j = vertexes->data().size() - 1; j >= 0; j--) { for (int j = vertexes->data().size() - 1; j >= 0; j--) {
const QVector<QVariant> &cv = vertexes->data().at(j); const QVector<QVariant> &cv = vertexes->data().at(j);
path.append(coordinates(cv.at(1).toInt(), cv.at(0).toInt(), path.append(coordinates(cv.at(1).toInt(), cv.at(0).toInt(),
COMF)); comf));
} }
} }
path.append(c[0]); path.append(c[0]);
@ -602,7 +620,7 @@ QVector<Coordinates> MapData::lineGeometry(const ISO8211::Record &r,
for (int j = 0; j < vertexes->data().size(); j++) { for (int j = 0; j < vertexes->data().size(); j++) {
const QVector<QVariant> &cv = vertexes->data().at(j); const QVector<QVariant> &cv = vertexes->data().at(j);
path.append(coordinates(cv.at(1).toInt(), cv.at(0).toInt(), path.append(coordinates(cv.at(1).toInt(), cv.at(0).toInt(),
COMF)); comf));
} }
} }
path.append(c[1]); path.append(c[1]);
@ -613,26 +631,26 @@ QVector<Coordinates> MapData::lineGeometry(const ISO8211::Record &r,
} }
Polygon MapData::polyGeometry(const ISO8211::Record &r, const RecordMap &vc, Polygon MapData::polyGeometry(const ISO8211::Record &r, const RecordMap &vc,
const RecordMap &ve, uint COMF) const RecordMap &ve, uint comf)
{ {
Polygon path; Polygon path;
QVector<Coordinates> v; QVector<Coordinates> v;
Coordinates c[2]; Coordinates c[2];
uint ORNT, USAG; uint ornt, usag;
quint8 type; quint8 type;
quint32 id; quint32 id;
const ISO8211::Field *FSPT = ISO8211::field(r, "FSPT"); const ISO8211::Field *fspt = ISO8211::field(r, FSPT);
if (!FSPT || FSPT->data().at(0).size() != 4) if (!fspt || fspt->data().at(0).size() != 4)
return Polygon(); return Polygon();
for (int i = 0; i < FSPT->data().size(); i++) { for (int i = 0; i < fspt->data().size(); i++) {
if (!parseNAME(FSPT, &type, &id, i) || type != RCNM_VE) if (!parseNAME(fspt, &type, &id, i) || type != RCNM_VE)
return Polygon(); return Polygon();
ORNT = FSPT->data().at(i).at(1).toUInt(); ornt = fspt->data().at(i).at(1).toUInt();
USAG = FSPT->data().at(i).at(2).toUInt(); usag = fspt->data().at(i).at(2).toUInt();
if (USAG == 2 && path.isEmpty()) { if (usag == 2 && path.isEmpty()) {
path.append(v); path.append(v);
v.clear(); v.clear();
} }
@ -640,55 +658,55 @@ Polygon MapData::polyGeometry(const ISO8211::Record &r, const RecordMap &vc,
RecordMapIterator it = ve.find(id); RecordMapIterator it = ve.find(id);
if (it == ve.constEnd()) if (it == ve.constEnd())
return Polygon(); return Polygon();
const ISO8211::Record &FRID = it.value(); const ISO8211::Record &frid = it.value();
const ISO8211::Field *VRPT = ISO8211::field(FRID, "VRPT"); const ISO8211::Field *vrpt = ISO8211::field(frid, VRPT);
if (!VRPT || VRPT->data().size() != 2) if (!vrpt || vrpt->data().size() != 2)
return Polygon(); return Polygon();
for (int j = 0; j < 2; j++) { for (int j = 0; j < 2; j++) {
if (!parseNAME(VRPT, &type, &id, j) || type != RCNM_VC) if (!parseNAME(vrpt, &type, &id, j) || type != RCNM_VC)
return Polygon(); return Polygon();
RecordMapIterator jt = vc.find(id); RecordMapIterator jt = vc.find(id);
if (jt == vc.constEnd()) if (jt == vc.constEnd())
return Polygon(); return Polygon();
c[j] = point(jt.value(), COMF); c[j] = point(jt.value(), comf);
if (c[j].isNull()) if (c[j].isNull())
return Polygon(); return Polygon();
} }
const ISO8211::Field *vertexes = SGXD(FRID); const ISO8211::Field *vertexes = SGXD(frid);
if (ORNT == 2) { if (ornt == 2) {
v.append(c[1]); v.append(c[1]);
if (USAG == 3) if (usag == 3)
v.append(Coordinates()); v.append(Coordinates());
if (vertexes) { if (vertexes) {
for (int j = vertexes->data().size() - 1; j >= 0; j--) { for (int j = vertexes->data().size() - 1; j >= 0; j--) {
const QVector<QVariant> &cv = vertexes->data().at(j); const QVector<QVariant> &cv = vertexes->data().at(j);
v.append(coordinates(cv.at(1).toInt(), cv.at(0).toInt(), v.append(coordinates(cv.at(1).toInt(), cv.at(0).toInt(),
COMF)); comf));
} }
} }
if (USAG == 3) if (usag == 3)
v.append(Coordinates()); v.append(Coordinates());
v.append(c[0]); v.append(c[0]);
} else { } else {
v.append(c[0]); v.append(c[0]);
if (USAG == 3) if (usag == 3)
v.append(Coordinates()); v.append(Coordinates());
if (vertexes) { if (vertexes) {
for (int j = 0; j < vertexes->data().size(); j++) { for (int j = 0; j < vertexes->data().size(); j++) {
const QVector<QVariant> &cv = vertexes->data().at(j); const QVector<QVariant> &cv = vertexes->data().at(j);
v.append(coordinates(cv.at(1).toInt(), cv.at(0).toInt(), v.append(coordinates(cv.at(1).toInt(), cv.at(0).toInt(),
COMF)); comf));
} }
} }
if (USAG == 3) if (usag == 3)
v.append(Coordinates()); v.append(Coordinates());
v.append(c[1]); v.append(c[1]);
} }
if (USAG == 2 && v.first() == v.last()) { if (usag == 2 && v.first() == v.last()) {
path.append(v); path.append(v);
v.clear(); v.clear();
} }
@ -704,12 +722,12 @@ MapData::Attributes MapData::attributes(const ISO8211::Record &r)
{ {
Attributes attr; Attributes attr;
const ISO8211::Field *ATTF = ISO8211::field(r, "ATTF"); const ISO8211::Field *attf = ISO8211::field(r, ATTF);
if (!(ATTF && ATTF->data().at(0).size() == 2)) if (!(attf && attf->data().at(0).size() == 2))
return attr; return attr;
for (int i = 0; i < ATTF->data().size(); i++) { for (int i = 0; i < attf->data().size(); i++) {
const QVector<QVariant> &av = ATTF->data().at(i); const QVector<QVariant> &av = attf->data().at(i);
attr.insert(av.at(0).toUInt(), av.at(1).toByteArray()); attr.insert(av.at(0).toUInt(), av.at(1).toByteArray());
} }
@ -722,64 +740,64 @@ MapData::Point *MapData::pointObject(const Sounding &s)
} }
MapData::Point *MapData::pointObject(const ISO8211::Record &r, MapData::Point *MapData::pointObject(const ISO8211::Record &r,
const RecordMap &vi, const RecordMap &vc, uint COMF, uint OBJL, uint HUNI) const RecordMap &vi, const RecordMap &vc, uint comf, uint objl, uint huni)
{ {
Coordinates c(pointGeometry(r, vi, vc, COMF)); Coordinates c(pointGeometry(r, vi, vc, comf));
return (c.isNull() ? 0 : new Point(OBJL, c, attributes(r), HUNI)); return (c.isNull() ? 0 : new Point(objl, c, attributes(r), huni));
} }
MapData::Line *MapData::lineObject(const ISO8211::Record &r, MapData::Line *MapData::lineObject(const ISO8211::Record &r,
const RecordMap &vc, const RecordMap &ve, uint COMF, uint OBJL) const RecordMap &vc, const RecordMap &ve, uint comf, uint objl)
{ {
QVector<Coordinates> path(lineGeometry(r, vc, ve, COMF)); QVector<Coordinates> path(lineGeometry(r, vc, ve, comf));
return (path.isEmpty() ? 0 : new Line(OBJL, path, attributes(r))); return (path.isEmpty() ? 0 : new Line(objl, path, attributes(r)));
} }
MapData::Poly *MapData::polyObject(const ISO8211::Record &r, MapData::Poly *MapData::polyObject(const ISO8211::Record &r,
const RecordMap &vc, const RecordMap &ve, uint COMF, uint OBJL, uint HUNI) const RecordMap &vc, const RecordMap &ve, uint comf, uint objl, uint huni)
{ {
Polygon path(polyGeometry(r, vc, ve, COMF)); Polygon path(polyGeometry(r, vc, ve, comf));
return (path.isEmpty() ? 0 : new Poly(OBJL, path, attributes(r), HUNI)); return (path.isEmpty() ? 0 : new Poly(objl, path, attributes(r), huni));
} }
bool MapData::processRecord(const ISO8211::Record &record, bool MapData::processRecord(const ISO8211::Record &record,
QVector<ISO8211::Record> &fe, RecordMap &vi, RecordMap &vc, RecordMap &ve, QVector<ISO8211::Record> &fe, RecordMap &vi, RecordMap &vc, RecordMap &ve,
RecordMap &vf, uint &COMF, uint &SOMF, uint &HUNI) RecordMap &vf, uint &comf, uint &somf, uint &huni)
{ {
if (record.size() < 2) if (record.size() < 2)
return false; return false;
const ISO8211::Field &f = record.at(1); const ISO8211::Field &f = record.at(1);
const QByteArray &ba = f.tag(); quint32 tag = f.tag();
if (ba == "VRID") { if (tag == VRID) {
if (f.data().at(0).size() < 2) if (f.data().at(0).size() < 2)
return false; return false;
int RCNM = f.data().at(0).at(0).toInt(); int rcnm = f.data().at(0).at(0).toInt();
uint RCID = f.data().at(0).at(1).toUInt(); uint rcid = f.data().at(0).at(1).toUInt();
switch (RCNM) { switch (rcnm) {
case RCNM_VI: case RCNM_VI:
vi.insert(RCID, record); vi.insert(rcid, record);
break; break;
case RCNM_VC: case RCNM_VC:
vc.insert(RCID, record); vc.insert(rcid, record);
break; break;
case RCNM_VE: case RCNM_VE:
ve.insert(RCID, record); ve.insert(rcid, record);
break; break;
case RCNM_VF: case RCNM_VF:
vf.insert(RCID, record); vf.insert(rcid, record);
break; break;
default: default:
return false; return false;
} }
} else if (ba == "FRID") { } else if (tag == FRID) {
fe.append(record); fe.append(record);
} else if (ba == "DSPM") { } else if (tag == DSPM) {
if (!(f.subfield("COMF", &COMF) && f.subfield("SOMF", &SOMF))) if (!(f.subfield(COMF, &comf) && f.subfield(SOMF, &somf)))
return false; return false;
if (!f.subfield("HUNI", &HUNI)) if (!f.subfield(HUNI, &huni))
return false; return false;
} }
@ -792,7 +810,7 @@ MapData::MapData(const QString &path)
QVector<ISO8211::Record> fe; QVector<ISO8211::Record> fe;
ISO8211 ddf(path); ISO8211 ddf(path);
ISO8211::Record record; ISO8211::Record record;
uint PRIM, OBJL, COMF = 1, SOMF = 1, HUNI = 1; uint prim, objl, comf = 1, somf = 1, huni = 1;
Poly *poly; Poly *poly;
Line *line; Line *line;
Point *point; Point *point;
@ -802,7 +820,7 @@ MapData::MapData(const QString &path)
if (!ddf.readDDR()) if (!ddf.readDDR())
return; return;
while (ddf.readRecord(record)) while (ddf.readRecord(record))
if (!processRecord(record, fe, vi, vc, ve, vf, COMF, SOMF, HUNI)) if (!processRecord(record, fe, vi, vc, ve, vf, comf, somf, huni))
qWarning("Invalid S-57 record"); qWarning("Invalid S-57 record");
for (int i = 0; i < fe.size(); i++) { for (int i = 0; i < fe.size(); i++) {
@ -811,39 +829,39 @@ MapData::MapData(const QString &path)
if (f.data().at(0).size() < 5) if (f.data().at(0).size() < 5)
continue; continue;
PRIM = f.data().at(0).at(2).toUInt(); prim = f.data().at(0).at(2).toUInt();
OBJL = f.data().at(0).at(4).toUInt(); objl = f.data().at(0).at(4).toUInt();
switch (PRIM) { switch (prim) {
case PRIM_P: case PRIM_P:
if (OBJL == SOUNDG) { if (objl == SOUNDG) {
QVector<Sounding> s(soundingGeometry(r, vi, vc, COMF, SOMF)); QVector<Sounding> s(soundingGeometry(r, vi, vc, comf, somf));
for (int i = 0; i < s.size(); i++) { for (int i = 0; i < s.size(); i++) {
point = pointObject(s.at(i)); point = pointObject(s.at(i));
pointBounds(point->pos(), min, max); pointBounds(point->pos(), min, max);
_points.Insert(min, max, point); _points.Insert(min, max, point);
} }
} else { } else {
if ((point = pointObject(r, vi, vc, COMF, OBJL, HUNI))) { if ((point = pointObject(r, vi, vc, comf, objl, huni))) {
pointBounds(point->pos(), min, max); pointBounds(point->pos(), min, max);
_points.Insert(min, max, point); _points.Insert(min, max, point);
} else } else
warning(f, PRIM); warning(f, prim);
} }
break; break;
case PRIM_L: case PRIM_L:
if ((line = lineObject(r, vc, ve, COMF, OBJL))) { if ((line = lineObject(r, vc, ve, comf, objl))) {
rectcBounds(line->bounds(), min, max); rectcBounds(line->bounds(), min, max);
_lines.Insert(min, max, line); _lines.Insert(min, max, line);
} else } else
warning(f, PRIM); warning(f, prim);
break; break;
case PRIM_A: case PRIM_A:
if ((poly = polyObject(r, vc, ve, COMF, OBJL, HUNI))) { if ((poly = polyObject(r, vc, ve, comf, objl, huni))) {
rectcBounds(poly->bounds(), min, max); rectcBounds(poly->bounds(), min, max);
_areas.Insert(min, max, poly); _areas.Insert(min, max, poly);
} else } else
warning(f, PRIM); warning(f, prim);
break; break;
} }
} }
@ -864,7 +882,7 @@ MapData::~MapData()
delete _points.GetAt(pit); delete _points.GetAt(pit);
} }
void MapData::points(const RectC &rect, QList<Point> *points) const void MapData::points(const RectC &rect, QList<Point> *points)
{ {
double min[2], max[2]; double min[2], max[2];
@ -874,18 +892,12 @@ void MapData::points(const RectC &rect, QList<Point> *points) const
_lines.Search(min, max, linePointCb, points); _lines.Search(min, max, linePointCb, points);
} }
void MapData::lines(const RectC &rect, QList<Line> *lines) const void MapData::polys(const RectC &rect, QList<Poly> *polygons,
QList<Line> *lines)
{ {
double min[2], max[2]; double min[2], max[2];
rectcBounds(rect, min, max); rectcBounds(rect, min, max);
_lines.Search(min, max, lineCb, lines); _lines.Search(min, max, lineCb, lines);
}
void MapData::polygons(const RectC &rect, QList<Poly> *polygons) const
{
double min[2], max[2];
rectcBounds(rect, min, max);
_areas.Search(min, max, polygonCb, polygons); _areas.Search(min, max, polygonCb, polygons);
} }

View File

@ -1,82 +1,21 @@
#ifndef ENC_MAPDATA_H #ifndef ENC_MAPDATA_H
#define ENC_MAPDATA_H #define ENC_MAPDATA_H
#include "common/rectc.h"
#include "common/rtree.h" #include "common/rtree.h"
#include "common/polygon.h"
#include "iso8211.h" #include "iso8211.h"
#include "data.h"
namespace ENC { namespace ENC {
class MapData class MapData : public Data
{ {
public: public:
typedef QMap<uint, QByteArray> Attributes;
class Poly {
public:
Poly(uint type, const Polygon &path, const Attributes &attr, uint HUNI);
RectC bounds() const {return _path.boundingRect();}
const Polygon &path() const {return _path;}
uint type() const {return _type;}
const Attributes &attributes() const {return _attr;}
uint HUNI() const {return _HUNI;}
private:
uint _type;
Polygon _path;
Attributes _attr;
uint _HUNI;
};
class Line {
public:
Line(uint type, const QVector<Coordinates> &path, const Attributes &attr);
RectC bounds() const;
const QVector<Coordinates> &path() const {return _path;}
uint type() const {return _type;}
const QString &label() const {return _label;}
const Attributes &attributes() const {return _attr;}
private:
uint _type;
QVector<Coordinates> _path;
QString _label;
Attributes _attr;
};
class Point {
public:
Point(uint type, const Coordinates &c, const Attributes &attr,
uint HUNI, bool polygon = false);
Point(uint type, const Coordinates &s, const QString &label);
const Coordinates &pos() const {return _pos;}
uint type() const {return _type;}
const QString &label() const {return _label;}
const Attributes &attributes() const {return _attr;}
bool polygon() const {return _polygon;}
bool operator<(const Point &other) const
{return _id < other._id;}
private:
uint _type;
Coordinates _pos;
QString _label;
quint64 _id;
Attributes _attr;
bool _polygon;
};
MapData(const QString &path); MapData(const QString &path);
~MapData(); virtual ~MapData();
void polygons(const RectC &rect, QList<Poly> *polygons) const; virtual void polys(const RectC &rect, QList<Poly> *polygons,
void lines(const RectC &rect, QList<Line> *lines) const; QList<Line> *lines);
void points(const RectC &rect, QList<Point> *points) const; virtual void points(const RectC &rect, QList<Point> *points);
private: private:
struct Sounding { struct Sounding {
@ -93,28 +32,28 @@ private:
typedef RTree<const Line*, double, 2> LineTree; typedef RTree<const Line*, double, 2> LineTree;
typedef RTree<const Point*, double, 2> PointTree; typedef RTree<const Point*, double, 2> PointTree;
static QVector<Sounding> soundings(const ISO8211::Record &r, uint COMF, static QVector<Sounding> soundings(const ISO8211::Record &r, uint comf,
uint SOMF); uint somf);
static QVector<Sounding> soundingGeometry(const ISO8211::Record &r, static QVector<Sounding> soundingGeometry(const ISO8211::Record &r,
const RecordMap &vi, const RecordMap &vc, uint COMF, uint SOMF); const RecordMap &vi, const RecordMap &vc, uint comf, uint somf);
static Coordinates pointGeometry(const ISO8211::Record &r, static Coordinates pointGeometry(const ISO8211::Record &r,
const RecordMap &vi, const RecordMap &vc, uint COMF); const RecordMap &vi, const RecordMap &vc, uint comf);
static QVector<Coordinates> lineGeometry(const ISO8211::Record &r, static QVector<Coordinates> lineGeometry(const ISO8211::Record &r,
const RecordMap &vc, const RecordMap &ve, uint COMF); const RecordMap &vc, const RecordMap &ve, uint comf);
static Polygon polyGeometry(const ISO8211::Record &r, const RecordMap &vc, static Polygon polyGeometry(const ISO8211::Record &r, const RecordMap &vc,
const RecordMap &ve, uint COMF); const RecordMap &ve, uint comf);
static Attributes attributes(const ISO8211::Record &r); static Attributes attributes(const ISO8211::Record &r);
static Point *pointObject(const Sounding &s); static Point *pointObject(const Sounding &s);
static Point *pointObject(const ISO8211::Record &r, const RecordMap &vi, static Point *pointObject(const ISO8211::Record &r, const RecordMap &vi,
const RecordMap &vc, uint COMF, uint OBJL, uint HUNI); const RecordMap &vc, uint comf, uint objl, uint huni);
static Line *lineObject(const ISO8211::Record &r, const RecordMap &vc, static Line *lineObject(const ISO8211::Record &r, const RecordMap &vc,
const RecordMap &ve, uint COMF, uint OBJL); const RecordMap &ve, uint comf, uint objl);
static Poly *polyObject(const ISO8211::Record &r, const RecordMap &vc, static Poly *polyObject(const ISO8211::Record &r, const RecordMap &vc,
const RecordMap &ve, uint COMF, uint OBJL, uint HUNI); const RecordMap &ve, uint comf, uint objl, uint huni);
static bool processRecord(const ISO8211::Record &record, static bool processRecord(const ISO8211::Record &record,
QVector<ISO8211::Record> &fe, RecordMap &vi, RecordMap &vc, RecordMap &ve, QVector<ISO8211::Record> &fe, RecordMap &vi, RecordMap &vc, RecordMap &ve,
RecordMap &vf, uint &COMF, uint &SOMF, uint &HUNI); RecordMap &vf, uint &comf, uint &somf, uint &huni);
PolygonTree _areas; PolygonTree _areas;
LineTree _lines; LineTree _lines;

View File

@ -14,6 +14,7 @@ using namespace ENC;
#define TEXT_EXTENT 160 #define TEXT_EXTENT 160
#define TSSLPT_SIZE 24 #define TSSLPT_SIZE 24
#define RANGE_FACTOR 4 #define RANGE_FACTOR 4
#define MAJOR_RANGE 10
static const float C1 = 0.866025f; /* sqrt(3)/2 */ static const float C1 = 0.866025f; /* sqrt(3)/2 */
static const QColor tsslptPen = QColor(0xeb, 0x49, 0xeb); static const QColor tsslptPen = QColor(0xeb, 0x49, 0xeb);
@ -27,14 +28,14 @@ static double angle(uint type, const QVariant &param)
? 90 + param.toDouble() : NAN; ? 90 + param.toDouble() : NAN;
} }
static bool showLabel(const QImage *img, const Range &range, int zoom, int type) bool RasterTile::showLabel(const QImage *img, int type) const
{ {
if (type>>16 == I_DISMAR) if (type>>16 == I_DISMAR)
return true; return true;
int limit = (!range.size()) int limit = (!_zoomRange.size())
? range.min() : range.min() + (range.size() + 1) / 2; ? _zoomRange.min() : _zoomRange.min() + (_zoomRange.size() + 1) / 2;
if ((img || (type>>16 == SOUNDG)) && (zoom < limit)) if ((img || (type>>16 == SOUNDG)) && (_zoom < limit))
return false; return false;
return true; return true;
@ -138,10 +139,10 @@ static void drawArrow(QPainter *painter, const QPolygonF &polygon, uint type)
} }
void RasterTile::drawArrows(QPainter *painter, void RasterTile::drawArrows(QPainter *painter,
const QList<MapData::Point> &points) const const QList<Data::Point> &points) const
{ {
for (int i = 0; i < points.size(); i++) { for (int i = 0; i < points.size(); i++) {
const MapData::Point &point = points.at(i); const Data::Point &point = points.at(i);
if (point.type()>>16 == TSSLPT || point.type()>>16 == RCTLPT) { if (point.type()>>16 == TSSLPT || point.type()>>16 == RCTLPT) {
QPolygonF polygon(tsslptArrow(ll2xy(point.pos()), QPolygonF polygon(tsslptArrow(ll2xy(point.pos()),
@ -152,11 +153,11 @@ void RasterTile::drawArrows(QPainter *painter,
} }
void RasterTile::drawPolygons(QPainter *painter, void RasterTile::drawPolygons(QPainter *painter,
const QList<MapData::Poly> &polygons) const const QList<Data::Poly> &polygons) const
{ {
for (int n = 0; n < _style->drawOrder().size(); n++) { for (int n = 0; n < _style->drawOrder().size(); n++) {
for (int i = 0; i < polygons.size(); i++) { for (int i = 0; i < polygons.size(); i++) {
const MapData::Poly &poly = polygons.at(i); const Data::Poly &poly = polygons.at(i);
if (poly.type() != _style->drawOrder().at(n)) if (poly.type() != _style->drawOrder().at(n))
continue; continue;
const Style::Polygon &style = _style->polygon(poly.type()); const Style::Polygon &style = _style->polygon(poly.type());
@ -168,8 +169,13 @@ void RasterTile::drawPolygons(QPainter *painter,
} else { } else {
if (style.brush() != Qt::NoBrush) { if (style.brush() != Qt::NoBrush) {
painter->setPen(Qt::NoPen); painter->setPen(Qt::NoPen);
QPainterPath path(painterPath(poly.path()));
if (poly.type() == TYPE(DRGARE)) {
painter->setBrush(Qt::white);
painter->drawPath(path);
}
painter->setBrush(style.brush()); painter->setBrush(style.brush());
painter->drawPath(painterPath(poly.path())); painter->drawPath(path);
} }
if (style.pen() != Qt::NoPen) { if (style.pen() != Qt::NoPen) {
painter->setPen(style.pen()); painter->setPen(style.pen());
@ -184,12 +190,12 @@ void RasterTile::drawPolygons(QPainter *painter,
} }
} }
void RasterTile::drawLines(QPainter *painter, const QList<MapData::Line> &lines) const void RasterTile::drawLines(QPainter *painter, const QList<Data::Line> &lines) const
{ {
painter->setBrush(Qt::NoBrush); painter->setBrush(Qt::NoBrush);
for (int i = 0; i < lines.size(); i++) { for (int i = 0; i < lines.size(); i++) {
const MapData::Line &line = lines.at(i); const Data::Line &line = lines.at(i);
const Style::Line &style = _style->line(line.type()); const Style::Line &style = _style->line(line.type());
if (!style.img().isNull()) { if (!style.img().isNull()) {
@ -215,16 +221,16 @@ void RasterTile::drawTextItems(QPainter *painter,
static QRectF lightRect(const QPointF &pos, double range) static QRectF lightRect(const QPointF &pos, double range)
{ {
return QRectF(pos.x() - range * RANGE_FACTOR, pos.y() - range * RANGE_FACTOR, double r = qMin(range * RANGE_FACTOR, (double)TEXT_EXTENT);
2*range * RANGE_FACTOR, 2*range * RANGE_FACTOR); return QRect(pos.x() - r, pos.y() - r, 2 * r, 2 * r);
} }
void RasterTile::drawSectorLights(QPainter *painter, void RasterTile::drawSectorLights(QPainter *painter,
const QList<SectorLight> &lights) const const QMultiMap<Coordinates, SectorLight> &lights) const
{ {
for (int i = 0; i < lights.size(); i++) { for (auto it = lights.cbegin(); it != lights.cend(); ++it) {
const SectorLight &l = lights.at(i); const SectorLight &l = it.value();
QPointF pos(ll2xy(l.pos)); QPointF pos(ll2xy(it.key()));
QRectF rect(lightRect(pos, (l.range == 0) ? 6 : l.range)); QRectF rect(lightRect(pos, (l.range == 0) ? 6 : l.range));
double a1 = -(l.end + 90); double a1 = -(l.end + 90);
double a2 = -(l.start + 90); double a2 = -(l.start + 90);
@ -256,49 +262,45 @@ void RasterTile::drawSectorLights(QPainter *painter,
} }
} }
void RasterTile::processPoints(QList<MapData::Point> &points, void RasterTile::processPoints(const QList<Data::Point> &points,
QList<TextItem*> &textItems, QList<TextItem*> &lights, QList<TextItem*> &textItems, QList<TextItem*> &lightItems,
QList<SectorLight> &sectorLights) QMultiMap<Coordinates, SectorLight> &sectorLights, bool overZoom) const
{ {
LightMap lightsMap; QMap<Coordinates, Style::Color> lights;
SignalSet signalsSet; QSet<Coordinates> sigs;
QSet<Coordinates> slMap;
int i; int i;
std::sort(points.begin(), points.end());
/* Lights & Signals */ /* Lights & Signals */
for (i = 0; i < points.size(); i++) { for (i = 0; i < points.size(); i++) {
const MapData::Point &point = points.at(i); const Data::Point &point = points.at(i);
if (point.type()>>16 == LIGHTS) { if (point.type()>>16 == LIGHTS) {
const MapData::Attributes &attr = point.attributes(); const Data::Attributes &attr = point.attributes();
Style::Color color = (Style::Color)(attr.value(COLOUR).toUInt()); Style::Color color = (Style::Color)(attr.value(COLOUR).toUInt());
double range = attr.value(VALNMR).toDouble(); double range = attr.value(VALNMR).toDouble();
if (attr.contains(SECTR1) if (attr.contains(SECTR1)
|| (range > 6 && !(point.type() & 0xFFFF))) { || (range >= MAJOR_RANGE && !(point.type() & 0xFFFF))) {
sectorLights.append(SectorLight(point.pos(), color, sectorLights.insert(point.pos(), SectorLight(color,
attr.value(LITVIS).toUInt(), range, attr.value(LITVIS).toUInt(), range,
attr.value(SECTR1).toDouble(), attr.value(SECTR2).toDouble())); attr.value(SECTR1).toDouble(), attr.value(SECTR2).toDouble()));
slMap.insert(point.pos());
} else } else
lightsMap.insert(point.pos(), color); lights.insert(point.pos(), color);
} else if (point.type()>>16 == FOGSIG) } else if (point.type()>>16 == FOGSIG)
signalsSet.insert(point.pos()); sigs.insert(point.pos());
else else
break; break;
} }
/* Everything else */ /* Everything else */
for ( ; i < points.size(); i++) { for ( ; i < points.size(); i++) {
const MapData::Point &point = points.at(i); const Data::Point &point = points.at(i);
QPoint pos(ll2xy(point.pos()).toPoint()); QPoint pos(ll2xy(point.pos()).toPoint());
const Style::Point &style = _style->point(point.type()); const Style::Point &style = _style->point(point.type());
const QString *label = point.label().isEmpty() ? 0 : &(point.label()); const QString *label = point.label().isEmpty() ? 0 : &(point.label());
const QImage *img = style.img().isNull() ? 0 : &style.img(); const QImage *img = style.img().isNull() ? 0 : &style.img();
const QFont *fnt = showLabel(img, _zoomRange, _zoom, point.type()) const QFont *fnt = (overZoom || showLabel(img, point.type()))
? _style->font(style.textFontSize()) : 0; ? _style->font(style.textFontSize()) : 0;
const QColor *color = &style.textColor(); const QColor *color = &style.textColor();
const QColor *hColor = style.haloColor().isValid() const QColor *hColor = style.haloColor().isValid()
@ -312,25 +314,25 @@ void RasterTile::processPoints(QList<MapData::Point> &points,
TextPointItem *item = new TextPointItem(pos + offset, label, fnt, img, TextPointItem *item = new TextPointItem(pos + offset, label, fnt, img,
color, hColor, 0, 2, rotate); color, hColor, 0, 2, rotate);
if (item->isValid() && (slMap.contains(point.pos()) if (item->isValid() && (sectorLights.contains(point.pos())
|| (point.polygon() && img) || !item->collides(textItems))) { || (point.polygon() && img) || !item->collides(textItems))) {
textItems.append(item); textItems.append(item);
if (lightsMap.contains(point.pos())) if (lights.contains(point.pos()))
lights.append(new TextPointItem(pos + _style->lightOffset(), lightItems.append(new TextPointItem(pos + _style->lightOffset(),
0, 0, _style->light(lightsMap.value(point.pos())), 0, 0, 0, 0)); 0, 0, _style->light(lights.value(point.pos())), 0, 0, 0, 0));
if (signalsSet.contains(point.pos())) if (sigs.contains(point.pos()))
lights.append(new TextPointItem(pos + _style->signalOffset(), lightItems.append(new TextPointItem(pos + _style->signalOffset(),
0, 0, _style->signal(), 0, 0, 0, 0)); 0, 0, _style->signal(), 0, 0, 0, 0));
} else } else
delete item; delete item;
} }
} }
void RasterTile::processLines(const QList<MapData::Line> &lines, void RasterTile::processLines(const QList<Data::Line> &lines,
QList<TextItem*> &textItems) QList<TextItem*> &textItems) const
{ {
for (int i = 0; i < lines.size(); i++) { for (int i = 0; i < lines.size(); i++) {
const MapData::Line &line = lines.at(i); const Data::Line &line = lines.at(i);
const Style::Line &style = _style->line(line.type()); const Style::Line &style = _style->line(line.type());
if (style.img().isNull() && style.pen() == Qt::NoPen) if (style.img().isNull() && style.pen() == Qt::NoPen)
@ -350,11 +352,46 @@ void RasterTile::processLines(const QList<MapData::Line> &lines,
} }
} }
void RasterTile::fetchData(QList<MapData::Poly> &polygons, void RasterTile::drawLevels(QPainter *painter, const QList<Level> &levels)
QList<MapData::Line> &lines, QList<MapData::Point> &points)
{ {
QPoint ttl(_rect.topLeft()); for (int i = levels.size() - 1; i >= 0; i--) {
QList<TextItem*> textItems, lightItems;
QMultiMap<Coordinates, SectorLight> sectorLights;
const Level &l = levels.at(i);
processPoints(l.points, textItems, lightItems, sectorLights, l.overZoom);
processLines(l.lines, textItems);
drawPolygons(painter, l.polygons);
drawLines(painter, l.lines);
drawArrows(painter, l.points);
drawTextItems(painter, lightItems);
drawSectorLights(painter, sectorLights);
drawTextItems(painter, textItems);
qDeleteAll(textItems);
qDeleteAll(lightItems);
}
}
QPainterPath RasterTile::shape(const QList<Data::Poly> &polygons) const
{
QPainterPath shp;
for (int i = 0; i < polygons.size(); i++) {
const Data::Poly &p = polygons.at(i);
if (p.type() == SUBTYPE(M_COVR, 1))
shp.addPath(painterPath(p.path()));
}
return shp;
}
QList<RasterTile::Level> RasterTile::fetchLevels()
{
QList<RasterTile::Level> list;
QPoint ttl(_rect.topLeft());
QRectF polyRect(ttl, QPointF(ttl.x() + _rect.width(), ttl.y() QRectF polyRect(ttl, QPointF(ttl.x() + _rect.width(), ttl.y()
+ _rect.height())); + _rect.height()));
RectD polyRectD(_transform.img2proj(polyRect.topLeft()), RectD polyRectD(_transform.img2proj(polyRect.topLeft()),
@ -367,50 +404,41 @@ void RasterTile::fetchData(QList<MapData::Poly> &polygons,
_transform.img2proj(pointRect.bottomRight())); _transform.img2proj(pointRect.bottomRight()));
RectC pointRectC(pointRectD.toRectC(_proj, 20)); RectC pointRectC(pointRectD.toRectC(_proj, 20));
if (_map) { for (int i = 0; i < _data.size(); i++) {
_map->lines(polyRectC, &lines); Level level;
_map->polygons(polyRectC, &polygons);
_map->points(pointRectC, &points); _data.at(i)->polys(polyRectC, &level.polygons, &level.lines);
} else { _data.at(i)->points(pointRectC, &level.points);
_atlas->polys(polyRectC, &polygons, &lines); level.overZoom = i > 0;
_atlas->points(pointRectC, &points);
std::sort(level.points.begin(), level.points.end());
if (!level.isNull())
list.append(level);
if (_data.size() > 1 && shape(level.polygons).contains(_rect))
break;
} }
return list;
} }
void RasterTile::render() void RasterTile::render()
{ {
QList<Level> levels(fetchLevels());
QImage img(_rect.width() * _ratio, _rect.height() * _ratio, QImage img(_rect.width() * _ratio, _rect.height() * _ratio,
QImage::Format_ARGB32_Premultiplied); QImage::Format_ARGB32_Premultiplied);
QList<MapData::Line> lines;
QList<MapData::Poly> polygons;
QList<MapData::Point> points;
QList<TextItem*> textItems, lights;
QList<SectorLight> sectorLights;
img.setDevicePixelRatio(_ratio); img.setDevicePixelRatio(_ratio);
img.fill(Qt::transparent); img.fill(Qt::transparent);
fetchData(polygons, lines, points);
processPoints(points, textItems, lights, sectorLights);
processLines(lines, textItems);
QPainter painter(&img); QPainter painter(&img);
painter.setRenderHint(QPainter::SmoothPixmapTransform); painter.setRenderHint(QPainter::SmoothPixmapTransform);
painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::Antialiasing);
painter.translate(-_rect.x(), -_rect.y()); painter.translate(-_rect.x(), -_rect.y());
drawPolygons(&painter, polygons); drawLevels(&painter, levels);
drawLines(&painter, lines);
drawArrows(&painter, points);
drawTextItems(&painter, lights);
drawSectorLights(&painter, sectorLights);
drawTextItems(&painter, textItems);
qDeleteAll(textItems);
qDeleteAll(lights);
//painter.setPen(Qt::red); //painter.setPen(Qt::red);
//painter.setBrush(Qt::NoBrush); //painter.setBrush(Qt::NoBrush);

View File

@ -5,7 +5,7 @@
#include "common/range.h" #include "common/range.h"
#include "map/projection.h" #include "map/projection.h"
#include "map/transform.h" #include "map/transform.h"
#include "mapdata.h" #include "data.h"
#include "style.h" #include "style.h"
#include "atlasdata.h" #include "atlasdata.h"
@ -17,14 +17,17 @@ class RasterTile
{ {
public: public:
RasterTile(const Projection &proj, const Transform &transform, RasterTile(const Projection &proj, const Transform &transform,
const Style *style, const MapData *data, int zoom, const Range &zoomRange, const Style *style, Data *data, int zoom,
const QRect &rect, qreal ratio) : const Range &zoomRange, const QRect &rect, qreal ratio) :
_proj(proj), _transform(transform), _style(style), _map(data), _atlas(0), _proj(proj), _transform(transform), _style(style),
_zoom(zoom), _zoomRange(zoomRange), _rect(rect), _ratio(ratio) {} _zoom(zoom), _zoomRange(zoomRange), _rect(rect), _ratio(ratio)
{
_data.append(data);
}
RasterTile(const Projection &proj, const Transform &transform, RasterTile(const Projection &proj, const Transform &transform,
const Style *style, AtlasData *data, int zoom, const Range &zoomRange, const Style *style, const QList<Data*> &data, int zoom,
const QRect &rect, qreal ratio) : const Range &zoomRange, const QRect &rect, qreal ratio) :
_proj(proj), _transform(transform), _style(style), _map(0), _atlas(data), _proj(proj), _transform(transform), _style(style), _data(data),
_zoom(zoom), _zoomRange(zoomRange), _rect(rect), _ratio(ratio) {} _zoom(zoom), _zoomRange(zoomRange), _rect(rect), _ratio(ratio) {}
int zoom() const {return _zoom;} int zoom() const {return _zoom;}
@ -36,11 +39,10 @@ public:
private: private:
struct SectorLight struct SectorLight
{ {
SectorLight(const Coordinates &pos, Style::Color color, uint visibility, SectorLight(Style::Color color, uint visibility, double range,
double range, double start, double end) : pos(pos), color(color), double start, double end) : color(color), visibility(visibility),
visibility(visibility), range(range), start(start), end(end) {} range(range), start(start), end(end) {}
Coordinates pos;
Style::Color color; Style::Color color;
uint visibility; uint visibility;
double range; double range;
@ -48,11 +50,16 @@ private:
double end; double end;
}; };
typedef QMap<Coordinates, Style::Color> LightMap; struct Level {
typedef QSet<Coordinates> SignalSet; QList<Data::Line> lines;
QList<Data::Poly> polygons;
QList<Data::Point> points;
bool overZoom;
bool isNull() const
{return lines.isEmpty() && polygons.isEmpty() && points.isEmpty();}
};
void fetchData(QList<MapData::Poly> &polygons, QList<MapData::Line> &lines,
QList<MapData::Point> &points);
QPointF ll2xy(const Coordinates &c) const QPointF ll2xy(const Coordinates &c) const
{return _transform.proj2img(_proj.ll2xy(c));} {return _transform.proj2img(_proj.ll2xy(c));}
QPainterPath painterPath(const Polygon &polygon) const; QPainterPath painterPath(const Polygon &polygon) const;
@ -60,25 +67,26 @@ private:
QVector<QPolygonF> polylineM(const QVector<Coordinates> &path) const; QVector<QPolygonF> polylineM(const QVector<Coordinates> &path) const;
QPolygonF tsslptArrow(const QPointF &p, qreal angle) const; QPolygonF tsslptArrow(const QPointF &p, qreal angle) const;
QPointF centroid(const QVector<Coordinates> &polygon) const; QPointF centroid(const QVector<Coordinates> &polygon) const;
void processPoints(QList<MapData::Point> &points, void processPoints(const QList<Data::Point> &points,
QList<TextItem*> &textItems, QList<TextItem *> &lights, QList<TextItem*> &textItems, QList<TextItem*> &lightItems,
QList<SectorLight> &sectorLights); QMultiMap<Coordinates, SectorLight> &sectorLights, bool overZoom) const;
void processLines(const QList<MapData::Line> &lines, void processLines(const QList<Data::Line> &lines,
QList<TextItem*> &textItems); QList<TextItem*> &textItems) const;
void drawArrows(QPainter *painter, const QList<MapData::Point> &points) const; void drawArrows(QPainter *painter, const QList<Data::Point> &points) const;
void drawPolygons(QPainter *painter, const QList<MapData::Poly> &polygons) const; void drawPolygons(QPainter *painter, const QList<Data::Poly> &polygons) const;
void drawLines(QPainter *painter, const QList<MapData::Line> &lines) const; void drawLines(QPainter *painter, const QList<Data::Line> &lines) const;
void drawTextItems(QPainter *painter, const QList<TextItem*> &textItems) const; void drawTextItems(QPainter *painter, const QList<TextItem*> &textItems) const;
void drawSectorLights(QPainter *painter, const QList<SectorLight> &lights) const; void drawSectorLights(QPainter *painter,
const QMultiMap<Coordinates, SectorLight> &lights) const;
static bool polyCb(MapData *data, void *context); bool showLabel(const QImage *img, int type) const;
static bool pointCb(MapData *data, void *context); void drawLevels(QPainter *painter, const QList<Level> &levels);
QList<Level> fetchLevels();
QPainterPath shape(const QList<Data::Poly> &polygons) const;
Projection _proj; Projection _proj;
Transform _transform; Transform _transform;
const Style *_style; const Style *_style;
const MapData *_map; QList<Data *> _data;
AtlasData *_atlas;
int _zoom; int _zoom;
Range _zoomRange; Range _zoomRange;
QRect _rect; QRect _rect;

View File

@ -27,7 +27,6 @@ static QFont pixelSizeFont(int pixelSize)
void Style::polygonStyle() void Style::polygonStyle()
{ {
_polygons[TYPE(M_COVR)] = Polygon(QBrush(QColor(0xff, 0xff, 0xff)));
_polygons[TYPE(LNDARE)] = Polygon(QBrush(QColor(0xe8, 0xe0, 0x64))); _polygons[TYPE(LNDARE)] = Polygon(QBrush(QColor(0xe8, 0xe0, 0x64)));
_polygons[TYPE(BUAARE)] = Polygon(QBrush(QColor(0xd9, 0x8b, 0x21))); _polygons[TYPE(BUAARE)] = Polygon(QBrush(QColor(0xd9, 0x8b, 0x21)));
_polygons[TYPE(BUISGL)] = Polygon(QBrush(QColor(0xd9, 0x8b, 0x21)), _polygons[TYPE(BUISGL)] = Polygon(QBrush(QColor(0xd9, 0x8b, 0x21)),
@ -141,6 +140,7 @@ void Style::polygonStyle()
1.5, Qt::DashLine)); 1.5, Qt::DashLine));
_polygons[TYPE(CBLARE)] = Polygon(QImage(":/marine/cable-area-line.png")); _polygons[TYPE(CBLARE)] = Polygon(QImage(":/marine/cable-area-line.png"));
_polygons[TYPE(PIPARE)] = Polygon(QImage(":/marine/pipeline-area-line.png")); _polygons[TYPE(PIPARE)] = Polygon(QImage(":/marine/pipeline-area-line.png"));
_polygons[SUBTYPE(MARKUL, 0)] = Polygon(QImage(":/marine/fishing-farm-line.png"));
_polygons[SUBTYPE(MARKUL, 3)] = Polygon(QImage(":/marine/fishing-farm-line.png")); _polygons[SUBTYPE(MARKUL, 3)] = Polygon(QImage(":/marine/fishing-farm-line.png"));
_polygons[TYPE(BERTHS)] = Polygon(Qt::NoBrush, QPen(QColor(0xeb, 0x49, 0xeb), _polygons[TYPE(BERTHS)] = Polygon(Qt::NoBrush, QPen(QColor(0xeb, 0x49, 0xeb),
1, Qt::DashLine)); 1, Qt::DashLine));
@ -152,19 +152,19 @@ void Style::polygonStyle()
1, Qt::DashDotLine)); 1, Qt::DashDotLine));
_drawOrder _drawOrder
<< TYPE(M_COVR) << TYPE(LNDARE) << SUBTYPE(DEPARE, 0) << TYPE(LNDARE) << SUBTYPE(DEPARE, 0) << SUBTYPE(DEPARE, 1)
<< SUBTYPE(DEPARE, 1) << SUBTYPE(DEPARE, 2) << SUBTYPE(DEPARE, 3) << SUBTYPE(DEPARE, 2) << SUBTYPE(DEPARE, 3) << TYPE(UNSARE)
<< TYPE(UNSARE) << SUBTYPE(DEPARE, 4) << SUBTYPE(DEPARE, 5) << SUBTYPE(DEPARE, 4) << SUBTYPE(DEPARE, 5) << SUBTYPE(DEPARE, 6)
<< SUBTYPE(DEPARE, 6) << TYPE(LAKARE) << TYPE(CANALS) << TYPE(DYKCON) << TYPE(LAKARE) << TYPE(CANALS) << TYPE(DYKCON) << TYPE(RIVERS)
<< TYPE(RIVERS) << TYPE(DRGARE) << TYPE(FAIRWY) << TYPE(LOKBSN) << TYPE(DRGARE) << TYPE(FAIRWY) << TYPE(LOKBSN) << TYPE(I_LOKBSN)
<< TYPE(I_LOKBSN) << TYPE(BUAARE) << TYPE(BUISGL) << TYPE(SILTNK) << TYPE(BUAARE) << TYPE(BUISGL) << TYPE(SILTNK) << TYPE(AIRARE)
<< TYPE(AIRARE) << TYPE(BRIDGE) << TYPE(I_BRIDGE) << TYPE(TUNNEL) << TYPE(BRIDGE) << TYPE(I_BRIDGE) << TYPE(TUNNEL) << TYPE(I_TERMNL)
<< TYPE(I_TERMNL) << TYPE(SLCONS) << TYPE(I_SLCONS) << TYPE(PONTON) << TYPE(SLCONS) << TYPE(I_SLCONS) << TYPE(PONTON) << TYPE(I_PONTON)
<< TYPE(I_PONTON) << TYPE(HULKES) << TYPE(I_HULKES) << TYPE(FLODOC) << TYPE(HULKES) << TYPE(I_HULKES) << TYPE(FLODOC) << TYPE(I_FLODOC)
<< TYPE(I_FLODOC) << TYPE(DRYDOC) << TYPE(DAMCON) << TYPE(PYLONS) << TYPE(DRYDOC) << TYPE(DAMCON) << TYPE(PYLONS) << TYPE(MORFAC)
<< TYPE(MORFAC) << TYPE(GATCON) << TYPE(I_GATCON) << TYPE(BERTHS) << TYPE(GATCON) << TYPE(I_GATCON) << TYPE(BERTHS) << TYPE(I_BERTHS)
<< TYPE(I_BERTHS) << SUBTYPE(I_BERTHS, 6) << TYPE(DMPGRD) << TYPE(TSEZNE) << SUBTYPE(I_BERTHS, 6) << TYPE(DMPGRD) << TYPE(TSEZNE) << TYPE(OBSTRN)
<< TYPE(OBSTRN) << TYPE(UWTROC) << TYPE(DWRTPT) << SUBTYPE(ACHARE, 1) << TYPE(UWTROC) << TYPE(DWRTPT) << SUBTYPE(ACHARE, 1)
<< SUBTYPE(ACHARE, 2) << SUBTYPE(ACHARE, 3) << SUBTYPE(ACHARE, 4) << SUBTYPE(ACHARE, 2) << SUBTYPE(ACHARE, 3) << SUBTYPE(ACHARE, 4)
<< SUBTYPE(ACHARE, 5) << SUBTYPE(ACHARE, 6) << SUBTYPE(ACHARE, 7) << SUBTYPE(ACHARE, 5) << SUBTYPE(ACHARE, 6) << SUBTYPE(ACHARE, 7)
<< SUBTYPE(ACHARE, 8) << SUBTYPE(ACHARE, 9) << SUBTYPE(I_ACHARE, 1) << SUBTYPE(ACHARE, 8) << SUBTYPE(ACHARE, 9) << SUBTYPE(I_ACHARE, 1)
@ -180,7 +180,8 @@ void Style::polygonStyle()
<< SUBTYPE(RESARE, 17) << SUBTYPE(I_RESARE, 17) << SUBTYPE(RESARE, 22) << SUBTYPE(RESARE, 17) << SUBTYPE(I_RESARE, 17) << SUBTYPE(RESARE, 22)
<< SUBTYPE(I_RESARE, 22) << SUBTYPE(RESARE, 23) << SUBTYPE(I_RESARE, 23) << SUBTYPE(I_RESARE, 22) << SUBTYPE(RESARE, 23) << SUBTYPE(I_RESARE, 23)
<< SUBTYPE(RESARE, 1) << TYPE(CBLARE) << TYPE(PIPARE) << TYPE(PRCARE) << SUBTYPE(RESARE, 1) << TYPE(CBLARE) << TYPE(PIPARE) << TYPE(PRCARE)
<< TYPE(I_TRNBSN) << SUBTYPE(MARKUL, 3) << TYPE(CONZNE); << TYPE(I_TRNBSN) << SUBTYPE(MARKUL, 0) << SUBTYPE(MARKUL, 3)
<< TYPE(CONZNE);
} }
void Style::lineStyle(qreal ratio) void Style::lineStyle(qreal ratio)
@ -393,6 +394,8 @@ void Style::pointStyle(qreal ratio)
_points[TYPE(LNDARE)].setHaloColor(QColor()); _points[TYPE(LNDARE)].setHaloColor(QColor());
_points[TYPE(LNDRGN)].setHaloColor(QColor()); _points[TYPE(LNDRGN)].setHaloColor(QColor());
_points[TYPE(RADRFL)] = Point(QImage(":/marine/radar-reflector.png")); _points[TYPE(RADRFL)] = Point(QImage(":/marine/radar-reflector.png"));
_points[SUBTYPE(MARKUL, 0)] = Point(QImage(":/marine/fishing-farm.png"));
_points[SUBTYPE(MARKUL, 3)] = Point(QImage(":/marine/fishing-farm.png"));
_points[SUBTYPE(I_BERTHS, 6)] = Point(QImage(":/marine/fleeting-area.png"), _points[SUBTYPE(I_BERTHS, 6)] = Point(QImage(":/marine/fleeting-area.png"),
Small); Small);
@ -482,6 +485,7 @@ Style::Style(qreal ratio)
_lightRed = QImage(":/marine/light-red.png"); _lightRed = QImage(":/marine/light-red.png");
_lightGreen = QImage(":/marine/light-green.png"); _lightGreen = QImage(":/marine/light-green.png");
_lightYellow = QImage(":/marine/light-yellow.png"); _lightYellow = QImage(":/marine/light-yellow.png");
_lightWhite = QImage(":/marine/light-white.png");
_lightOffset = QPoint(11, 11); _lightOffset = QPoint(11, 11);
_signal = QImage(":/marine/fog-signal.png"); _signal = QImage(":/marine/fog-signal.png");
_signalOffset = QPoint(-9, 9); _signalOffset = QPoint(-9, 9);
@ -541,6 +545,7 @@ const QImage *Style::light(Color color) const
case Green: case Green:
return &_lightGreen; return &_lightGreen;
case White: case White:
return &_lightWhite;
case Yellow: case Yellow:
case Amber: case Amber:
case Orange: case Orange:
@ -558,6 +563,7 @@ QColor Style::color(Style::Color c)
case Green: case Green:
return Qt::green; return Qt::green;
case White: case White:
return Qt::white;
case Yellow: case Yellow:
case Amber: case Amber:
case Orange: case Orange:

View File

@ -121,7 +121,7 @@ private:
/* Fonts and images must be initialized after QGuiApplication! */ /* Fonts and images must be initialized after QGuiApplication! */
QFont _small, _normal, _large; QFont _small, _normal, _large;
QImage _light, _lightRed, _lightGreen, _lightYellow, _signal; QImage _light, _lightRed, _lightGreen, _lightYellow, _lightWhite, _signal;
QPoint _lightOffset, _signalOffset; QPoint _lightOffset, _signalOffset;
}; };

64
src/map/IMG/light.h Normal file
View File

@ -0,0 +1,64 @@
#ifndef IMG_LIGHT_H
#define IMG_LIGHT_H
#include <QVector>
#include <QDebug>
namespace IMG {
class Light
{
public:
enum Color {None, Red, Green, White, Blue, Yellow, Violet, Amber};
class Sector
{
public:
Sector() : _color(None), _angle(0), _range(0) {}
Sector(Color color, quint32 angle, quint32 range)
: _color(color), _angle(angle), _range(range) {}
Color color() const {return _color;}
quint32 angle() const {return _angle;}
quint32 range() const {return _range;}
private:
Color _color;
quint32 _angle;
quint32 _range;
};
Light() : _color(None), _range(0) {}
Light(Color color, quint32 range) : _color(color), _range(range) {}
Light(const QVector<Sector> &sectors)
: _color(None), _range(0), _sectors(sectors) {}
Color color() const {return _color;}
quint32 range() const {return _range;}
const QVector<Sector> &sectors() const {return _sectors;}
private:
Color _color;
quint32 _range;
QVector<Sector> _sectors;
};
}
#ifndef QT_NO_DEBUG
inline QDebug operator<<(QDebug dbg, const IMG::Light::Sector &sector)
{
dbg.nospace() << "Sector(" << sector.color() << ", " << sector.angle()
<< ", " << sector.range() << ")";
return dbg.space();
}
inline QDebug operator<<(QDebug dbg, const IMG::Light &light)
{
dbg.nospace() << "Light(" << light.color() << ", " << light.range() << ", "
<< light.sectors() << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG
#endif // IMG_LIGHT_H

View File

@ -1,52 +0,0 @@
#ifndef IMG_LIGHTS_H
#define IMG_LIGHTS_H
#include <QVector>
#include <QDebug>
namespace IMG {
class Lights
{
public:
enum Color {None, Red, Green, White, Blue, Yellow, Violet, Amber};
struct Sector
{
Sector() : color(None), angle(0), range(0) {}
Sector(Color color, quint32 angle, quint32 range)
: color(color), angle(angle), range(range) {}
Color color;
quint32 angle;
quint32 range;
};
Lights() : color(None), range(0) {}
bool isSectorLight() const
{return ((color && range > 6) || !sectors.isEmpty());}
Color color;
quint32 range;
QVector<Sector> sectors;
};
}
#ifndef QT_NO_DEBUG
inline QDebug operator<<(QDebug dbg, const IMG::Lights::Sector &sector)
{
dbg.nospace() << "Sector(" << sector.color << ", " << sector.angle
<< ", " << sector.range << ")";
return dbg.space();
}
inline QDebug operator<<(QDebug dbg, const IMG::Lights &lights)
{
dbg.nospace() << "Lights(" << lights.color << ", " << lights.range << ", "
<< lights.sectors << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG
#endif // IMG_LIGHTS_H

View File

@ -14,7 +14,7 @@
#include "map/matrix.h" #include "map/matrix.h"
#include "label.h" #include "label.h"
#include "raster.h" #include "raster.h"
#include "lights.h" #include "light.h"
#include "zoom.h" #include "zoom.h"
namespace IMG { namespace IMG {
@ -56,7 +56,7 @@ public:
Coordinates coordinates; Coordinates coordinates;
Label label; Label label;
Lights lights; QVector<Light> lights;
quint64 id; quint64 id;
quint32 type; quint32 type;
quint32 flags; quint32 flags;

View File

@ -19,6 +19,7 @@ using namespace IMG;
#define TEXT_EXTENT 160 #define TEXT_EXTENT 160
#define ICON_PADDING 2 #define ICON_PADDING 2
#define RANGE_FACTOR 4 #define RANGE_FACTOR 4
#define MAJOR_RANGE 10
#define ROAD 0 #define ROAD 0
#define WATER 1 #define WATER 1
@ -228,43 +229,55 @@ void RasterTile::drawTextItems(QPainter *painter,
static QRect lightRect(const QPoint &pos, quint32 range) static QRect lightRect(const QPoint &pos, quint32 range)
{ {
return QRect(pos.x() - range * RANGE_FACTOR, pos.y() - range * RANGE_FACTOR, quint32 r = qMin(range * RANGE_FACTOR, (quint32)TEXT_EXTENT);
2*range * RANGE_FACTOR, 2*range * RANGE_FACTOR); return QRect(pos.x() - r, pos.y() - r, 2 * r, 2 * r);
} }
void RasterTile::drawSectorLights(QPainter *painter, void RasterTile::drawSectorLights(QPainter *painter,
const QList<const MapData::Point *> &lights) const const QList<const MapData::Point*> &lights) const
{ {
for (int i = 0; i < lights.size(); i++) { for (int i = 0; i < lights.size(); i++) {
const MapData::Point *p = lights.at(i); const MapData::Point *p = lights.at(i);
QPoint pos(p->coordinates.lon(), p->coordinates.lat()); QPoint pos(p->coordinates.lon(), p->coordinates.lat());
QMap<Sector, quint32> rangeMap;
if (p->lights.sectors.size()) { for (int j = 0; j < p->lights.size(); j++) {
for (int j = 0; j < p->lights.sectors.size(); j++) { const Light &l = p->lights.at(j);
const Lights::Sector &start = p->lights.sectors.at(j);
const Lights::Sector &end = (j == p->lights.sectors.size() - 1)
? p->lights.sectors.at(0) : p->lights.sectors.at(j+1);
if (start.color) { if (l.sectors().size()) {
double a1 = -(end.angle / 10.0 + 90.0); for (int k = 0; k < l.sectors().size(); k++) {
double a2 = -(start.angle / 10.0 + 90.0); const Light::Sector &start = l.sectors().at(k);
const Light::Sector &end = (k == l.sectors().size() - 1)
? l.sectors().at(0) : l.sectors().at(k+1);
quint32 angle = end.angle() - start.angle();
if (start.color() && (angle || start.range() >= MAJOR_RANGE)) {
quint32 range = start.range() ? start.range() : 6;
Sector s(start.color(), start.angle(), end.angle());
if (rangeMap.value(s) >= range)
continue;
else
rangeMap.insert(s, range);
double a1 = -(end.angle() / 10.0 + 90.0);
double a2 = -(start.angle() / 10.0 + 90.0);
if (a1 > a2) if (a1 > a2)
a2 += 360; a2 += 360;
double as = (a2 - a1); double as = (a2 - a1);
if (as == 0) if (as == 0)
as = 360; as = 360;
QRect rect(lightRect(pos, start.range ? start.range : 6)); QRect rect(lightRect(pos, range));
painter->setPen(QPen(Qt::black, 6, Qt::SolidLine, painter->setPen(QPen(Qt::black, 6, Qt::SolidLine,
Qt::FlatCap)); Qt::FlatCap));
painter->drawArc(rect, a1 * 16, as * 16); painter->drawArc(rect, a1 * 16, as * 16);
painter->setPen(QPen(Style::color(start.color), 4, painter->setPen(QPen(Style::color(start.color()), 4,
Qt::SolidLine, Qt::FlatCap)); Qt::SolidLine, Qt::FlatCap));
painter->drawArc(rect, a1 * 16, as * 16); painter->drawArc(rect, a1 * 16, as * 16);
if (a2 - a1 != 0) { if (angle) {
QLineF ln(pos, QPointF(pos.x() + rect.width(), pos.y())); QLineF ln(pos, QPointF(pos.x() + rect.width(),
pos.y()));
ln.setAngle(a1); ln.setAngle(a1);
painter->setPen(QPen(Qt::black, 1, Qt::DashLine)); painter->setPen(QPen(Qt::black, 1, Qt::DashLine));
painter->drawLine(ln); painter->drawLine(ln);
@ -273,19 +286,25 @@ void RasterTile::drawSectorLights(QPainter *painter,
} }
} }
} }
} else { } else if (l.color() && l.range() >= MAJOR_RANGE) {
QRect rect(lightRect(pos, p->lights.range)); Sector s(l.color(), 0, 3600);
if (rangeMap.value(s) >= l.range())
continue;
else
rangeMap.insert(s, l.range());
QRect rect(lightRect(pos, l.range()));
painter->setPen(QPen(Qt::black, 6, Qt::SolidLine, Qt::FlatCap)); painter->setPen(QPen(Qt::black, 6, Qt::SolidLine, Qt::FlatCap));
painter->drawArc(rect, 0, 360 * 16); painter->drawArc(rect, 0, 360 * 16);
painter->setPen(QPen(Style::color(p->lights.color), 4, painter->setPen(QPen(Style::color(l.color()), 4, Qt::SolidLine,
Qt::SolidLine, Qt::FlatCap)); Qt::FlatCap));
painter->drawArc(rect, 0, 360 * 16); painter->drawArc(rect, 0, 360 * 16);
} }
} }
}
} }
static void removeDuplicitLabel(QList<TextItem *> &labels, const QString &text, static void removeDuplicitLabel(QList<TextItem*> &labels, const QString &text,
const QRectF &tileRect) const QRectF &tileRect)
{ {
for (int i = 0; i < labels.size(); i++) { for (int i = 0; i < labels.size(); i++) {
@ -456,8 +475,47 @@ void RasterTile::processShields(const QList<MapData::Poly> &lines,
} }
} }
static bool sectorLight(const QVector<Light> &lights)
{
for (int i = 0; i < lights.size(); i++) {
const Light &l = lights.at(i);
if (l.color() && l.range() >= MAJOR_RANGE)
return true;
for (int j = 0; j < l.sectors().size(); j++) {
const Light::Sector &start = l.sectors().at(j);
const Light::Sector &end = (j == l.sectors().size() - 1)
? l.sectors().at(0) : l.sectors().at(j+1);
quint32 angle = end.angle() - start.angle();
if (start.color() && (angle || start.range() >= MAJOR_RANGE))
return true;
}
}
return false;
}
static Light::Color ordinaryLight(const QVector<Light> &lights)
{
for (int i = 0; i < lights.size(); i++) {
const Light &l = lights.at(i);
if (l.color() && l.range() < MAJOR_RANGE)
return l.color();
for (int j = 0; j < l.sectors().size(); j++) {
const Light::Sector &start = l.sectors().at(j);
const Light::Sector &end = (j == l.sectors().size() - 1)
? l.sectors().at(0) : l.sectors().at(j+1);
quint32 angle = end.angle() - start.angle();
if (start.color() && !angle && start.range() < MAJOR_RANGE)
return start.color();
}
}
return Light::None;
}
void RasterTile::processPoints(QList<MapData::Point> &points, void RasterTile::processPoints(QList<MapData::Point> &points,
QList<TextItem*> &textItems, QList<const MapData::Point*> &lights) QList<TextItem*> &textItems, QList<TextItem*> &lights,
QList<const MapData::Point*> &sectorLights)
{ {
std::sort(points.begin(), points.end()); std::sort(points.begin(), points.end());
@ -466,9 +524,10 @@ void RasterTile::processPoints(QList<MapData::Point> &points,
const Style *style = _data->style(); const Style *style = _data->style();
const Style::Point &ps = style->point(point.type); const Style::Point &ps = style->point(point.type);
bool poi = Style::isPOI(point.type); bool poi = Style::isPOI(point.type);
bool sl = sectorLight(point.lights);
if (point.lights.isSectorLight()) if (sl)
lights.append(&point); sectorLights.append(&point);
const QString *label = point.label.text().isEmpty() const QString *label = point.label.text().isEmpty()
? 0 : &(point.label.text()); ? 0 : &(point.label.text());
@ -490,15 +549,17 @@ void RasterTile::processPoints(QList<MapData::Point> &points,
TextPointItem *item = new TextPointItem(pos + offset, label, fnt, img, TextPointItem *item = new TextPointItem(pos + offset, label, fnt, img,
color, hcolor, 0, ICON_PADDING); color, hcolor, 0, ICON_PADDING);
if (item->isValid() && (point.lights.isSectorLight() if (item->isValid() && (sl || !item->collides(textItems))) {
|| !item->collides(textItems))) {
textItems.append(item); textItems.append(item);
if (point.lights.color && !point.lights.isSectorLight()) Light::Color color = ordinaryLight(point.lights);
textItems.append(new TextPointItem(pos + style->lightOffset(), if (color)
0, 0, style->light(point.lights.color), 0, 0, 0, 0)); lights.append(new TextPointItem(pos + style->lightOffset(),
0, 0, style->light(color), 0, 0, 0, 0));
} else } else
delete item; delete item;
} }
} }
void RasterTile::fetchData(QList<MapData::Poly> &polygons, void RasterTile::fetchData(QList<MapData::Poly> &polygons,
@ -583,8 +644,8 @@ void RasterTile::render()
QList<MapData::Poly> polygons; QList<MapData::Poly> polygons;
QList<MapData::Poly> lines; QList<MapData::Poly> lines;
QList<MapData::Point> points; QList<MapData::Point> points;
QList<TextItem*> textItems; QList<TextItem*> textItems, lights;
QList<const MapData::Point*> lights; QList<const MapData::Point*> sectorLights;
QImage arrows[2]; QImage arrows[2];
arrows[ROAD] = Util::svg2img(":/symbols/oneway.svg", _ratio); arrows[ROAD] = Util::svg2img(":/symbols/oneway.svg", _ratio);
@ -595,7 +656,7 @@ void RasterTile::render()
ll2xy(lines); ll2xy(lines);
ll2xy(points); ll2xy(points);
processPoints(points, textItems, lights); processPoints(points, textItems, lights, sectorLights);
processPolygons(polygons, textItems); processPolygons(polygons, textItems);
processLines(lines, textItems, arrows); processLines(lines, textItems, arrows);
@ -610,9 +671,11 @@ void RasterTile::render()
drawPolygons(&painter, polygons); drawPolygons(&painter, polygons);
drawHillShading(&painter); drawHillShading(&painter);
drawLines(&painter, lines); drawLines(&painter, lines);
drawSectorLights(&painter, lights); drawTextItems(&painter, lights);
drawSectorLights(&painter, sectorLights);
drawTextItems(&painter, textItems); drawTextItems(&painter, textItems);
qDeleteAll(lights);
qDeleteAll(textItems); qDeleteAll(textItems);
//painter.setPen(Qt::red); //painter.setPen(Qt::red);

Some files were not shown because too many files have changed in this diff Show More