1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2025-07-22 23:04:23 +02:00

Compare commits

...

63 Commits

Author SHA1 Message Date
092c56468c Update the theme to the latest Mapsforge version 2023-08-08 00:53:06 +02:00
d064cedbbe Apply the Mapsforge maps zoom levels offset
Offset the Mapsforge zoom level when fetching data/rendering the tiles to get
the expected data/sizes/widths for the tiles at the given zoom level.
2023-08-05 18:56:55 +02:00
8ab728f81d Desktop QT still needs to be installed manually for Android build 2023-08-05 09:59:35 +02:00
6670dc32b5 Build arm64_v8a targets on Android 2023-08-05 09:51:04 +02:00
61b51e5596 Be more tolerant to unknown file header data 2023-08-04 09:34:36 +02:00
4bf81e020f Yet another code cleanup 2023-08-03 00:39:56 +02:00
4bcbce671d Merge remote-tracking branch 'weblate/master' 2023-08-01 23:39:55 +02:00
e07e109c7d Code cleanup 2023-08-01 23:38:33 +02:00
e9609c5167 Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (467 of 467 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/nb_NO/
2023-08-01 23:38:30 +02:00
dcf45475ba Show the arrows even when no label is set 2023-08-01 23:21:49 +02:00
6ce2a63a1c Version++ 2023-07-31 23:38:50 +02:00
3e8b54f605 Added hi-dpi one-way street (+ water ways) arrows 2023-07-31 23:36:14 +02:00
c6af082fa3 Merge branch 'origin/master' into Weblate. 2023-07-24 19:03:57 +02:00
66036f6cd7 Yet another one-way arrows improvement 2023-07-24 19:04:19 +02:00
c644ea2170 Translated using Weblate (Esperanto)
Currently translated at 94.4% (441 of 467 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/eo/
2023-07-23 11:03:14 +02:00
04041a2d9c Translated using Weblate (Ukrainian)
Currently translated at 99.1% (463 of 467 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/uk/
2023-07-23 11:03:13 +02:00
6a128c8eb4 Translated using Weblate (Russian)
Currently translated at 100.0% (467 of 467 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/ru/
2023-07-23 11:03:13 +02:00
1a08e50c3e Translated using Weblate (Finnish)
Currently translated at 97.6% (456 of 467 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/fi/
2023-07-23 11:03:13 +02:00
dd0dec54df Merge branch 'origin/master' into Weblate. 2023-07-14 10:33:46 +02:00
dfda3a6630 Use less agressive one-way street arrows 2023-07-14 10:33:45 +02:00
c03e24ce52 Merge branch 'origin/master' into Weblate. 2023-07-14 09:54:24 +02:00
96e762beb5 Properly mark one-way streets in data from NET links 2023-07-14 09:52:27 +02:00
cbd2d99739 Merge branch 'origin/master' into Weblate. 2023-07-13 12:00:41 +02:00
b4be5ea206 Display one-way streets info in IMG maps 2023-07-13 11:59:53 +02:00
3e0b732a65 Merge branch 'origin/master' into Weblate. 2023-07-06 10:57:05 +02:00
56c77df176 Build universal x86_64/arm64 binaries on OS X 2023-07-06 10:56:56 +02:00
1871f85acc Yet another ENV path fix 2023-07-06 10:19:26 +02:00
4b51d30e00 Merge branch 'origin/master' into Weblate. 2023-07-06 10:19:13 +02:00
3ec636632f Fixed ENV file path 2023-07-06 10:12:32 +02:00
40c41b88e3 Merge branch 'origin/master' into Weblate. 2023-07-06 10:12:17 +02:00
fcd02e4978 Merge branch 'origin/master' into Weblate. 2023-07-06 10:07:33 +02:00
5e1af275b8 Switched to MSVC 2022 and Qt 6.5 2023-07-06 10:07:13 +02:00
0f4bb95d57 Merge branch 'origin/master' into Weblate. 2023-07-04 20:27:49 +02:00
cd220216dd Do not affect the map object scaling when resizing the tiles 2023-07-04 20:27:41 +02:00
2efac25629 Merge branch 'origin/master' into Weblate. 2023-06-30 09:58:22 +02:00
0d6b02f466 Removed obsolete include 2023-06-30 09:55:35 +02:00
2f74c4bbb6 Merge branch 'origin/master' into Weblate. 2023-06-29 07:22:32 +02:00
059c515175 Added graph pinch zooming
Fixes #501
2023-06-29 07:22:11 +02:00
raf
66ba8268a3 Translated using Weblate (Catalan)
Currently translated at 100.0% (467 of 467 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/ca/
2023-06-28 12:52:20 +02:00
e328321b19 Merge branch 'origin/master' into Weblate. 2023-06-23 13:56:58 +02:00
1dc963b133 Revert "Removed SDK/buildtools workaround"
This reverts commit f0036bfd28.
2023-06-23 10:08:30 +02:00
f0036bfd28 Removed SDK/buildtools workaround 2023-06-23 09:33:04 +02:00
688861bf65 Code cleanup 2023-06-23 09:30:44 +02:00
8b20124533 Translated using Weblate (Hungarian)
Currently translated at 100.0% (467 of 467 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/hu/
2023-06-20 12:52:11 +02:00
c449024584 Version++ 2023-06-14 00:42:16 +02:00
41188360bf Make the Mapsforge tiles sufficient large for the layout 2023-06-14 00:40:00 +02:00
1086a74f99 Back to Qt 6.4 on Windows 2023-06-12 01:03:49 +02:00
7b5a1c701d Switched Qt 6 CI builds to Qt 6.5 2023-06-11 08:30:43 +02:00
9afeaf672a Properly match symbols to captions 2023-06-10 08:11:18 +02:00
5ddd63e697 Do not limit text that was not inserted 2023-06-06 07:32:42 +02:00
88fa1ed786 Some more Mapsforge maps rendering improvements 2023-06-06 07:18:31 +02:00
1233d20a21 Added support for lineSymbols in Mapsforge maps 2023-06-04 23:56:00 +02:00
1746eddb8d Code cleanup 2023-06-03 13:35:29 +02:00
ecda5103c8 Properly handle Mapsforge style menus 2023-05-31 01:01:42 +02:00
50b0ff1c56 Cosmetics 2023-05-29 23:19:28 +02:00
2b300fab54 Code cleanup 2023-05-29 23:19:16 +02:00
961061b643 Added rescue station 2023-05-28 11:28:12 +02:00
8bebea53ad Added LNDELV elevation values 2023-05-28 10:40:39 +02:00
c3b484bb75 Properly include std::isnan() 2023-05-26 21:57:45 +02:00
d6d43baec5 Optimization 2023-05-26 21:30:27 +02:00
c6c3e0978c Use generic icon rotate instead of special icon draw functions 2023-05-26 21:28:44 +02:00
320b04c3fa Added support for line "dy" parameter 2023-05-22 23:29:04 +02:00
ab7185bd25 Version++ 2023-05-22 23:28:50 +02:00
51 changed files with 855 additions and 437 deletions

View File

@ -1,23 +1,23 @@
version: 13.3.{build}
version: 13.6.{build}
configuration:
- Release
image:
- Visual Studio 2019
- Visual Studio 2022
environment:
NSISDIR: C:\Program Files (x86)\NSIS
OPENSSLDIR: C:\OpenSSL-v111-Win64\bin
matrix:
- QTDIR: C:\Qt\5.15\msvc2019_64
- QTDIR: C:\Qt\6.4\msvc2019_64
- QTDIR: C:\Qt\6.5\msvc2019_64
NSISDEF: /DQT6
install:
- cmd: |-
set PATH=%QTDIR%\bin;%NSISDIR%;%PATH%
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat
call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat
build_script:
- cmd: |-

View File

@ -28,14 +28,16 @@ jobs:
- name: Install Qt (Desktop)
uses: jurplel/install-qt-action@v3
with:
aqtversion: '==3.1.*'
version: '6.4.0'
- name: Install Qt (Android)
uses: jurplel/install-qt-action@v3
with:
aqtversion: '==3.1.*'
version: '6.4.0'
target: 'android'
arch: 'android_armv7'
modules: qtpositioning qt5compat qtserialport
arch: 'android_arm64_v8a'
modules: qtimageformats qtpositioning qtserialport qt5compat
- name: Install Android OpenSSL
run: git clone https://github.com/KDAB/android_openssl.git
- name: Create localization
@ -47,5 +49,5 @@ jobs:
- name: Upload artifacts
uses: actions/upload-artifact@v3
with:
name: GPXSee-armv7.apk
name: GPXSee-arm64_v8a.apk
path: android-build/build/outputs/apk/debug/android-build-debug.apk

View File

@ -39,12 +39,12 @@ jobs:
- name: Install Qt
uses: jurplel/install-qt-action@v3
with:
version: '6.4.3'
version: '6.5.1'
modules: qtpositioning qt5compat qtserialport
- name: Create localization
run: lrelease gpxsee.pro
- name: Configure build
run: qmake gpxsee.pro
run: qmake gpxsee.pro QMAKE_APPLE_DEVICE_ARCHS="x86_64h arm64"
- name: Build project
run: make -j3
- name: Create DMG

View File

@ -871,7 +871,7 @@
<caption fill="#5555AA" font-family="serif" font-size="14" font-style="bold_italic"
k="name" priority="20" stroke="#FFFFFF" stroke-width="2.0" />
</rule>
<rule e="node" k="place" v="isolated_dwelling" zoom-min="15">
<rule e="node" k="place" v="isolated_dwelling|neighbourhood" zoom-min="15">
<caption fill="#333380" font-size="12" font-style="bold" k="name" priority="5"
stroke="#FFFFFF" stroke-width="2.0" />
</rule>
@ -972,22 +972,26 @@
<!-- emergency -->
<rule e="any" k="*" v="*">
<rule e="any" k="amenity|building" v="hospital|clinic" zoom-min="15">
<rule e="any" k="amenity|building" v="hospital|clinic" zoom-min="14">
<symbol id="hospital" src=":/mapsforge/symbols/health/hospital.svg" />
<rule e="any" k="*" v="*" zoom-min="17">
<caption fill="#DA0092" font-size="12" font-style="bold" k="name" position="above"
priority="10" stroke="#FFFFFF" stroke-width="2.0" symbol-id="hospital" />
</rule>
</rule>
<rule e="any" k="amenity" v="pharmacy" zoom-min="13">
<rule e="any" k="amenity" v="pharmacy" zoom-min="15">
<symbol id="pharmacy" src=":/mapsforge/symbols/health/pharmacy.svg" />
<caption fill="#DA0092" font-size="12" font-style="bold" k="name" position="above"
priority="10" stroke="#FFFFFF" stroke-width="2.0" symbol-id="pharmacy" />
<rule e="any" k="*" v="*" zoom-min="17">
<caption fill="#DA0092" font-size="12" font-style="bold" k="name" position="above"
priority="10" stroke="#FFFFFF" stroke-width="2.0" symbol-id="pharmacy" />
</rule>
</rule>
<rule e="any" k="amenity" v="doctors" zoom-min="14">
<rule e="any" k="amenity" v="doctors" zoom-min="15">
<symbol id="doctors" src=":/mapsforge/symbols/health/doctors2.svg" />
<caption fill="#DA0092" font-size="12" font-style="bold" k="name" position="above"
priority="10" stroke="#FFFFFF" stroke-width="2.0" symbol-id="doctors" />
<rule e="any" k="*" v="*" zoom-min="17">
<caption fill="#DA0092" font-size="12" font-style="bold" k="name" position="above"
priority="10" stroke="#FFFFFF" stroke-width="2.0" symbol-id="doctors" />
</rule>
</rule>
<rule e="any" k="amenity|building" v="embassy" zoom-min="17">
<symbol id="embassy" src=":/mapsforge/symbols/poi/embassy2.svg" />
@ -1040,21 +1044,21 @@
</rule>
<rule e="any" k="tourism" v="hostel" zoom-min="13">
<symbol id="hostel" src=":/mapsforge/symbols/accommodation/hostel.svg" />
<rule e="any" k="*" v="*" zoom-min="18">
<rule e="any" k="*" v="*" zoom-min="17">
<caption fill="#0092DA" font-size="12" font-style="bold" k="name" stroke="#FFFFFF"
stroke-width="2" symbol-id="hostel" />
</rule>
</rule>
<rule e="any" k="tourism|building" v="hotel|guest_house|motel" zoom-min="13">
<symbol id="hotel" src=":/mapsforge/symbols/accommodation/hotel2.svg" />
<rule e="any" k="*" v="*" zoom-min="18">
<rule e="any" k="*" v="*" zoom-min="17">
<caption display="never" fill="#0092DA" font-size="12" font-style="bold" k="name"
stroke="#FFFFFF" stroke-width="2" symbol-id="hotel" />
</rule>
</rule>
<rule e="any" k="tourism" v="chalet" zoom-min="13">
<symbol id="chalet" src=":/mapsforge/symbols/accommodation/chalet.svg" />
<rule e="any" k="*" v="*" zoom-min="18">
<rule e="any" k="*" v="*" zoom-min="17">
<caption fill="#0092DA" font-size="12" font-style="bold" k="name" stroke="#FFFFFF"
stroke-width="2" symbol-id="chalet" />
</rule>
@ -1109,7 +1113,7 @@
<!-- food -->
<rule e="any" k="*" v="*">
<rule e="any" k="amenity" v="restaurant" zoom-min="14">
<rule e="any" k="amenity" v="restaurant" zoom-min="15">
<symbol id="restaurant" src=":/mapsforge/symbols/food/restaurant.svg" />
<rule e="node" k="*" v="*" zoom-min="16">
<caption fill="#734A08" font-size="12" font-style="bold" k="name" position="above"
@ -1132,25 +1136,25 @@
<!-- shopping -->
<rule e="any" k="*" v="*">
<rule e="any" k="shop" v="supermarket|department_store|mall" zoom-min="14">
<rule e="any" k="shop" v="supermarket|department_store|mall" zoom-min="15">
<symbol src=":/mapsforge/symbols/shopping/supermarket.svg" />
</rule>
<rule e="any" k="shop" v="convenience|general|kiosk" zoom-min="14">
<rule e="any" k="shop" v="convenience|general|kiosk" zoom-min="15">
<symbol src=":/mapsforge/symbols/shopping/convenience.svg" />
</rule>
<rule e="any" k="shop" v="bakery" zoom-min="14">
<rule e="any" k="shop" v="bakery" zoom-min="15">
<symbol src=":/mapsforge/symbols/shopping/bakery.svg" />
</rule>
<rule e="any" k="amenity" v="fuel" zoom-min="13">
<rule e="any" k="amenity" v="fuel" zoom-min="14">
<symbol id="fuel" src=":/mapsforge/symbols/transport/fuel.svg" />
<rule e="any" k="*" v="*" zoom-min="18">
<rule e="any" k="*" v="*" zoom-min="17">
<caption fill="#AC39AC" font-size="12" font-style="bold" k="name" stroke="#FFFFFF"
stroke-width="2.0" symbol-id="fuel" />
</rule>
</rule>
<rule e="any" k="amenity" v="marketplace" zoom-min="15">
<symbol id="marketplace" src=":/mapsforge/symbols/shopping/marketplace.svg" />
<rule e="any" k="*" v="*" zoom-min="18">
<rule e="any" k="*" v="*" zoom-min="17">
<caption fill="#AC39AC" font-size="12" font-style="bold" k="name" stroke="#FFFFFF"
stroke-width="2.0" symbol-id="marketplace" />
</rule>
@ -1197,14 +1201,14 @@
</rule>
<rule e="any" k="amenity" v="atm" zoom-min="15">
<symbol id="atm" src=":/mapsforge/symbols/money/atm2.svg" />
<rule e="any" k="*" v="*" zoom-min="18">
<rule e="any" k="*" v="*" zoom-min="17">
<caption fill="#666666" font-size="12" font-style="bold" k="name" position="above"
stroke="#FFFFFF" stroke-width="2.0" symbol-id="atm" />
</rule>
</rule>
<rule e="any" k="amenity" v="bank" zoom-min="15">
<symbol id="bank" src=":/mapsforge/symbols/money/bank2.svg" />
<rule e="any" k="*" v="*" zoom-min="18">
<rule e="any" k="*" v="*" zoom-min="17">
<caption fill="#666666" font-size="12" font-style="bold" k="name" position="above"
stroke="#FFFFFF" stroke-width="2.0" symbol-id="bank" />
</rule>
@ -1237,35 +1241,35 @@
</rule>
<rule e="any" k="leisure" v="playground" zoom-min="16">
<symbol id="playground" src=":/mapsforge/symbols/amenity/playground.svg" />
<rule e="any" k="*" v="*" zoom-min="18">
<rule e="any" k="*" v="*" zoom-min="17">
<caption fill="#39AC39" font-size="12" font-style="bold" k="name" stroke="#FFFFFF"
stroke-width="2.0" symbol-id="playground" />
</rule>
</rule>
<rule e="any" k="amenity" v="kindergarten" zoom-min="17">
<symbol id="nursery" src=":/mapsforge/symbols/education/nursery3.svg" />
<rule e="any" k="*" v="*" zoom-min="18">
<rule e="any" k="*" v="*" zoom-min="17">
<caption fill="#39AC39" font-size="12" font-style="bold" k="name" stroke="#FFFFFF"
stroke-width="2.0" symbol-id="nursery" />
</rule>
</rule>
<rule e="any" k="amenity|building" v="library" zoom-min="17">
<symbol id="library" src=":/mapsforge/symbols/amenity/library.svg" />
<rule e="any" k="*" v="*" zoom-min="18">
<rule e="any" k="*" v="*" zoom-min="17">
<caption fill="#39AC39" font-size="12" font-style="bold" k="name" stroke="#FFFFFF"
stroke-width="2.0" symbol-id="library" />
</rule>
</rule>
<rule e="any" k="amenity|building" v="school" zoom-min="17">
<symbol id="school" src=":/mapsforge/symbols/education/school.svg" />
<rule e="any" k="*" v="*" zoom-min="18">
<rule e="any" k="*" v="*" zoom-min="17">
<caption fill="#39AC39" font-size="12" font-style="bold" k="name" stroke="#FFFFFF"
stroke-width="2.0" symbol-id="school" />
</rule>
</rule>
<rule e="any" k="amenity" v="theatre" zoom-min="17">
<symbol id="theatre" src=":/mapsforge/symbols/tourist/theatre.svg" />
<rule e="any" k="*" v="*" zoom-min="18">
<rule e="any" k="*" v="*" zoom-min="17">
<caption fill="#734A08" font-size="12" font-style="bold" k="name" stroke="#FFFFFF"
stroke-width="2.0" symbol-id="theatre" />
</rule>
@ -1343,25 +1347,25 @@
</rule>
<rule e="node" k="man_made" v="lighthouse" zoom-min="14">
<symbol id="lighthouse" src=":/mapsforge/symbols/transport/lighthouse.svg" />
<rule e="any" k="*" v="*" zoom-min="18">
<rule e="any" k="*" v="*" zoom-min="17">
<caption fill="#0092DA" font-size="12" font-style="bold" k="name" position="above"
stroke="#FFFFFF" stroke-width="2.0" symbol-id="lighthouse" />
</rule>
</rule>
<rule e="any" k="building" v="church|cathedral|chapel" zoom-min="14">
<rule e="any" k="building" v="church|cathedral|chapel" zoom-min="15">
<symbol src=":/mapsforge/symbols/place_of_worship/christian.svg" />
</rule>
<rule e="any" k="amenity" v="place_of_worship" zoom-min="14">
<rule e="any" k="amenity" v="place_of_worship" zoom-min="15">
<rule e="any" k="religion" v="buddhist">
<symbol id="buddhist" src=":/mapsforge/symbols/place_of_worship/buddhist.svg" />
<rule e="any" k="*" v="*" zoom-min="18">
<rule e="any" k="*" v="*" zoom-min="17">
<caption fill="#666666" font-size="12" font-style="bold" k="name"
position="above" stroke="#FFFFFF" stroke-width="2.0" symbol-id="buddhist" />
</rule>
</rule>
<rule e="any" k="religion" v="christian">
<symbol id="christian" src=":/mapsforge/symbols/place_of_worship/christian.svg" />
<rule e="any" k="*" v="*" zoom-min="18">
<rule e="any" k="*" v="*" zoom-min="17">
<caption fill="#666666" font-size="12" font-style="bold" k="name"
position="above" stroke="#FFFFFF" stroke-width="2.0"
symbol-id="christian" />
@ -1369,35 +1373,35 @@
</rule>
<rule e="any" k="religion" v="hindu">
<symbol id="hindu" src=":/mapsforge/symbols/place_of_worship/hindu.svg" />
<rule e="any" k="*" v="*" zoom-min="18">
<rule e="any" k="*" v="*" zoom-min="17">
<caption fill="#666666" font-size="12" font-style="bold" k="name"
position="above" stroke="#FFFFFF" stroke-width="2.0" symbol-id="hindu" />
</rule>
</rule>
<rule e="any" k="religion" v="jewish">
<symbol id="jewish" src=":/mapsforge/symbols/place_of_worship/jewish.svg" />
<rule e="any" k="*" v="*" zoom-min="18">
<rule e="any" k="*" v="*" zoom-min="17">
<caption fill="#666666" font-size="12" font-style="bold" k="name"
position="above" stroke="#FFFFFF" stroke-width="2.0" symbol-id="jewish" />
</rule>
</rule>
<rule e="any" k="religion" v="muslim">
<symbol id="muslim" src=":/mapsforge/symbols/place_of_worship/islamic.svg" />
<rule e="any" k="*" v="*" zoom-min="18">
<rule e="any" k="*" v="*" zoom-min="17">
<caption fill="#666666" font-size="12" font-style="bold" k="name"
position="above" stroke="#FFFFFF" stroke-width="2.0" symbol-id="muslim" />
</rule>
</rule>
<rule e="any" k="religion" v="shinto">
<symbol id="shinto" src=":/mapsforge/symbols/place_of_worship/shinto.svg" />
<rule e="any" k="*" v="*" zoom-min="18">
<rule e="any" k="*" v="*" zoom-min="17">
<caption fill="#666666" font-size="12" font-style="bold" k="name"
position="above" stroke="#FFFFFF" stroke-width="2.0" symbol-id="shinto" />
</rule>
</rule>
<rule e="any" k="religion" v="~|*">
<symbol id="religion-unknown" src=":/mapsforge/symbols/place_of_worship/unknown.svg" />
<rule e="any" k="*" v="*" zoom-min="18">
<rule e="any" k="*" v="*" zoom-min="17">
<caption fill="#666666" font-size="12" font-style="bold" k="name"
position="above" stroke="#FFFFFF" stroke-width="2.0"
symbol-id="religion-unknown" />
@ -1409,15 +1413,15 @@
<!-- sports -->
<rule e="any" k="*" v="*">
<rule e="any" k="leisure" v="water_park" zoom-min="14">
<rule e="any" k="leisure" v="water_park" zoom-min="15">
<symbol src=":/mapsforge/symbols/sport/swimming_outdoor.svg" />
</rule>
<rule e="way" k="leisure" v="~" zoom-min="14">
<rule e="way" k="leisure" v="~" zoom-min="15">
<rule e="way" k="sport" v="swimming">
<symbol src=":/mapsforge/symbols/sport/swimming_outdoor.svg" />
</rule>
</rule>
<rule e="node" k="sport" v="swimming" zoom-min="14">
<rule e="node" k="sport" v="swimming" zoom-min="15">
<symbol src=":/mapsforge/symbols/sport/swimming_outdoor.svg" />
</rule>
<rule e="any" k="sport" v="soccer" zoom-min="16">

View File

@ -3,7 +3,8 @@ unix:!macx:!android {
} else {
TARGET = GPXSee
}
VERSION = 13.3
VERSION = 13.6
QT += core \
gui \

View File

@ -55,6 +55,14 @@
<file alias="transform-move_32@2x.png">icons/GUI/transform-move_32@2x.png</file>
</qresource>
<!-- Common map stuff -->
<qresource prefix="/map">
<file alias="arrow.png">icons/map/arrow.png</file>
<file alias="arrow@2x.png">icons/map/arrow@2x.png</file>
<file alias="water-arrow.png">icons/map/water-arrow.png</file>
<file alias="water-arrow@2x.png">icons/map/water-arrow@2x.png</file>
</qresource>
<!-- POIs (IMG & ENC style) -->
<qresource prefix="/POI">
<file alias="airfield-11.png">icons/map/POI/airfield-11.png</file>
@ -198,6 +206,9 @@
<file alias="building.png">icons/map/marine/building.png</file>
<file alias="fog-signal.png">icons/map/marine/fog-signal.png</file>
<file alias="construction.png">icons/map/marine/construction.png</file>
<file alias="radio-call.png">icons/map/marine/radio-call.png</file>
<file alias="current.png">icons/map/marine/current.png</file>
<file alias="rescue-station.png">icons/map/marine/rescue-station.png</file>
</qresource>
<!-- Mapsforge rendertheme -->

BIN
icons/map/arrow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 B

BIN
icons/map/arrow@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 B

BIN
icons/map/water-arrow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 B

View File

@ -1320,7 +1320,7 @@
<message>
<location filename="../src/GUI/motioninfoitem.cpp" line="87"/>
<source>kn</source>
<translation>km</translation>
<translation>nus</translation>
</message>
<message>
<location filename="../src/GUI/motioninfoitem.cpp" line="90"/>

View File

@ -712,13 +712,13 @@
<location filename="../src/GUI/gui.cpp" line="907"/>
<location filename="../src/GUI/gui.cpp" line="925"/>
<source>CRS directory:</source>
<translation type="unfinished"></translation>
<translation>CRS-dosierujo:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="913"/>
<location filename="../src/GUI/gui.cpp" line="931"/>
<source>Symbols directory:</source>
<translation type="unfinished"></translation>
<translation>Dosierujo de simboloj:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="960"/>

View File

@ -425,7 +425,7 @@
<message>
<location filename="../src/GUI/gui.cpp" line="217"/>
<source>Open directory...</source>
<translation type="unfinished"></translation>
<translation>Avaa hakemisto</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="236"/>
@ -878,7 +878,7 @@
<location filename="../src/GUI/gui.cpp" line="907"/>
<location filename="../src/GUI/gui.cpp" line="925"/>
<source>CRS directory:</source>
<translation type="unfinished"></translation>
<translation>CRS-hakemisto:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="915"/>

View File

@ -1019,6 +1019,7 @@
<source>%n files</source>
<translation>
<numerusform>%n fájl</numerusform>
<numerusform>%n fájl</numerusform>
</translation>
</message>
</context>

View File

@ -845,22 +845,22 @@
<message>
<location filename="../src/GUI/gui.cpp" line="882"/>
<source>Zoom in</source>
<translation>Forstørr</translation>
<translation>Zoom inn</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="884"/>
<source>Zoom out</source>
<translation>Forminsk</translation>
<translation>Zoom ut</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="886"/>
<source>Digital zoom</source>
<translation>Digital forstørrelse</translation>
<translation>Digital zoom</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="887"/>
<source>Zoom</source>
<translation>Forstørr</translation>
<translation>Zoom</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="888"/>
@ -1822,12 +1822,12 @@
<message>
<location filename="../src/GUI/optionsdialog.cpp" line="662"/>
<source>The printed area is approximately the display area. The map zoom level does not change.</source>
<translation>Det utskrevne området er omtrent det samme som visningsområdet. Kartforstørrelsesnivået endrer seg ikke.</translation>
<translation>Det utskrevne området er omtrent det samme som visningsområdet. Kartets zoomnivå endres ikke.</translation>
</message>
<message>
<location filename="../src/GUI/optionsdialog.cpp" line="664"/>
<source>The zoom level will be changed so that the whole content (tracks/waypoints) fits to the printed area and the map resolution is as close as possible to the print resolution.</source>
<translation>Forstørrelsesnivået vil endres slik at hele innholdet (spor/veipunkter) passer med utskrevet område, og kartoppløsningen er lik utskriftsoppløsningen som mulig.</translation>
<translation>Zoomnivået vil endres slik at hele innholdet (spor/veipunkter) passer med utskrevet område og kartoppløsningen er lik utskriftsoppløsningen som mulig.</translation>
</message>
<message>
<location filename="../src/GUI/optionsdialog.cpp" line="680"/>

View File

@ -878,7 +878,7 @@
<location filename="../src/GUI/gui.cpp" line="907"/>
<location filename="../src/GUI/gui.cpp" line="925"/>
<source>CRS directory:</source>
<translation type="unfinished"></translation>
<translation>Каталог CRS:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="915"/>
@ -1428,12 +1428,12 @@
<message>
<location filename="../src/GUI/optionsdialog.cpp" line="70"/>
<source>Select the proper coordinate reference system (CRS) of maps without a CRS definition (JNX, KMZ and World file maps).</source>
<translation type="unfinished"></translation>
<translation>Выберите правильную систему координат (CRS) для карт без определения CRS (форматы JNX, KMZ и World file).</translation>
</message>
<message>
<location filename="../src/GUI/optionsdialog.cpp" line="73"/>
<source>Select the desired projection of vector maps (IMG, Mapsforge and ENC maps). The projection must be valid for the whole map area.</source>
<translation type="unfinished"></translation>
<translation>Выберите нужную проекцию векторных карт (IMG, Mapsforge и ENC). Проекция должна быть действительна для всей области карты.</translation>
</message>
<message>
<location filename="../src/GUI/optionsdialog.cpp" line="77"/>

View File

@ -712,7 +712,7 @@
<location filename="../src/GUI/gui.cpp" line="907"/>
<location filename="../src/GUI/gui.cpp" line="925"/>
<source>CRS directory:</source>
<translation type="unfinished"></translation>
<translation>Каталог CRS:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="913"/>

View File

@ -37,7 +37,7 @@ Unicode true
; The name of the installer
Name "GPXSee"
; Program version
!define VERSION "13.3"
!define VERSION "13.6"
; The file to write
OutFile "GPXSee-${VERSION}_x64.exe"

View File

@ -2,6 +2,7 @@
#include <QGraphicsScene>
#include <QEvent>
#include <QMouseEvent>
#include <QGestureEvent>
#include <QScrollBar>
#include <QGraphicsSimpleTextItem>
#include <QPalette>
@ -37,6 +38,8 @@ GraphView::GraphView(QWidget *parent)
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setBackgroundBrush(QBrush(palette().brush(QPalette::Base)));
viewport()->setAttribute(Qt::WA_AcceptTouchEvents);
grabGesture(Qt::PinchGesture);
_xAxis = new AxisItem(AxisItem::X);
_xAxis->setZValue(1.0);
@ -381,6 +384,27 @@ void GraphView::wheelEvent(QWheelEvent *e)
QGraphicsView::wheelEvent(e);
}
void GraphView::pinchGesture(QPinchGesture *gesture)
{
QPinchGesture::ChangeFlags changeFlags = gesture->changeFlags();
if (changeFlags & QPinchGesture::ScaleFactorChanged) {
QPointF pos = mapToScene(gesture->centerPoint().toPoint());
QRectF gr(_grid->boundingRect());
QPointF r(pos.x() / gr.width(), pos.y() / gr.height());
_zoom = qMax(_zoom * gesture->scaleFactor(), 1.0);
redraw();
QRectF ngr(_grid->boundingRect());
QPointF npos(mapFromScene(QPointF(r.x() * ngr.width(),
r.y() * ngr.height())));
QScrollBar *sb = horizontalScrollBar();
sb->setSliderPosition(sb->sliderPosition() + npos.x()
- gesture->centerPoint().x());
}
}
void GraphView::paintEvent(QPaintEvent *e)
{
QRectF viewRect(mapToScene(rect()).boundingRect());
@ -577,3 +601,19 @@ void GraphView::changeEvent(QEvent *e)
QGraphicsView::changeEvent(e);
}
bool GraphView::event(QEvent *event)
{
if (event->type() == QEvent::Gesture)
return gestureEvent(static_cast<QGestureEvent*>(event));
return QGraphicsView::event(event);
}
bool GraphView::gestureEvent(QGestureEvent *event)
{
if (QGesture *pinch = event->gesture(Qt::PinchGesture))
pinchGesture(static_cast<QPinchGesture *>(pinch));
return true;
}

View File

@ -18,6 +18,8 @@ class PathItem;
class GridItem;
class QGraphicsSimpleTextItem;
class GraphicsScene;
class QGestureEvent;
class QPinchGesture;
class GraphView : public QGraphicsView
{
@ -59,6 +61,7 @@ protected:
void wheelEvent(QWheelEvent *e);
void changeEvent(QEvent *e);
void paintEvent(QPaintEvent *e);
bool event(QEvent *event);
const QString &yLabel() const {return _yLabel;}
const QString &yUnits() const {return _yUnits;}
@ -94,6 +97,8 @@ private:
void removeItem(QGraphicsItem *item);
void addItem(QGraphicsItem *item);
bool singleGraph() const;
bool gestureEvent(QGestureEvent *event);
void pinchGesture(QPinchGesture *gesture);
GraphicsScene *_scene;

View File

@ -218,18 +218,6 @@ quint32 DataStream::readTranslatedObjects(QList<TranslatedString> &objects)
}
static quint32 readFprsRecord(DataStream &stream)
{
RecordHeader rh;
quint16 s1;
quint8 rs, s2, s3, s4;
rs = stream.readRecordHeader(rh);
stream >> s1 >> s2 >> s3 >> s4;
return rs + 5;
}
static quint32 readFileDataRecord(DataStream &stream)
{
RecordHeader rh;
@ -771,12 +759,15 @@ bool GPIParser::readFileHeader(DataStream &stream, quint32 &ebs)
stream >> s5 >> s6 >> s7 >> s8 >> s9 >> s10;
stream.skipRawData(s10);
ds = sizeof(magic) + 10 + s10;
if (rh.flags & 8)
ds += readFprsRecord(stream);
ebs = (s8 & 0x4) ? s9 * 8 + 8 : 0;
if (stream.status() != QDataStream::Ok || ds != rh.size) {
if (ds > rh.size)
stream.setStatus(QDataStream::ReadCorruptData);
else if (ds < rh.size)
stream.skipRawData(rh.size - ds);
if (stream.status() != QDataStream::Ok) {
_errorString = "Invalid file header";
return false;
} else

View File

@ -23,6 +23,7 @@ static QMap<uint,uint> orderMapInit()
map.insert(TYPE(FOGSIG), 0);
map.insert(TYPE(CGUSTA), 1);
map.insert(TYPE(RSCSTA), 1);
map.insert(SUBTYPE(BUAARE, 1), 2);
map.insert(SUBTYPE(BUAARE, 5), 3);
map.insert(SUBTYPE(BUAARE, 4), 4);
@ -264,6 +265,13 @@ MapData::Point::Point(uint type, const Coordinates &c, const QString &label,
if (_label.isEmpty())
_label = sistat(type & 0xFF);
_type = TYPE(SISTAT);
} else if (type>>16 == LNDELV && params.size()) {
if (_label.isEmpty())
_label = QString::fromLatin1(params.at(0))
+ QString::fromUtf8("\xE2\x80\x89m");
else
_label += "\n(" + QString::fromLatin1(params.at(0))
+ "\xE2\x80\x89m)";
}
}
@ -552,7 +560,8 @@ MapData::Attr MapData::pointAttr(const ISO8211::Record &r, uint OBJL)
if ((OBJL == I_DISMAR && key == I_WTWDIS)
|| (OBJL == RDOCAL && key == ORIENT)
|| (OBJL == I_RDOCAL && key == ORIENT)
|| (OBJL == CURENT && key == ORIENT))
|| (OBJL == CURENT && key == ORIENT)
|| (OBJL == LNDELV && key == ELEVAT))
params[0] = av.at(1).toByteArray();
if ((OBJL == I_RDOCAL && key == COMCHA)
|| (OBJL == RDOCAL && key == COMCHA)

View File

@ -70,6 +70,7 @@
#define RAILWY 106
#define RCRTCL 108
#define RECTRC 109
#define RSCSTA 111
#define RESARE 112
#define RIVERS 114
#define ROADWY 116

View File

@ -10,15 +10,11 @@
using namespace ENC;
#define TEXT_EXTENT 160
#define TSSLPT_SIZE 0.005 /* ll */
#define RDOCAL_SIZE 12 /* px */
#define CURENT_SIZE 12 /* px */
typedef QMap<Coordinates, const MapData::Point*> PointMap;
const float C1 = 0.866025f; /* sqrt(3)/2 */
static const float C1 = 0.866025f; /* sqrt(3)/2 */
static const QColor haloColor(Qt::white);
static struct {
@ -105,67 +101,12 @@ static Coordinates centroid(const QVector<Coordinates> &polygon)
return Coordinates(cx * factor, cy * factor);
}
static QImage *rdocalArrow(qreal angle)
static double angle(uint type, const QVariant &param)
{
QImage *img = new QImage(RDOCAL_SIZE*2, RDOCAL_SIZE*2,
QImage::Format_ARGB32_Premultiplied);
img->fill(Qt::transparent);
QPainter p(img);
p.setRenderHint(QPainter::Antialiasing);
p.setPen(QPen(QColor("#eb49eb"), 1));
uint bt = type>>16;
QPointF arrow[3];
arrow[0] = QPointF(img->width()/2, img->height()/2);
arrow[1] = arrow[0] + QPointF(qSin(angle - M_PI/3) * RDOCAL_SIZE,
qCos(angle - M_PI/3) * RDOCAL_SIZE);
arrow[2] = arrow[0] + QPointF(qSin(angle - M_PI + M_PI/3) * RDOCAL_SIZE,
qCos(angle - M_PI + M_PI/3) * RDOCAL_SIZE);
QLineF l(arrow[1], arrow[2]);
QPointF pt(l.pointAt(0.5));
p.translate(arrow[0] - pt);
p.drawPolyline(QPolygonF() << arrow[1] << arrow[0] << arrow[2]);
p.drawEllipse(pt, RDOCAL_SIZE/2, RDOCAL_SIZE/2);
return img;
}
static QImage *currentArrow(qreal angle)
{
QImage *img = new QImage(CURENT_SIZE*2, CURENT_SIZE*2,
QImage::Format_ARGB32_Premultiplied);
img->fill(Qt::transparent);
QPainter p(img);
p.setRenderHint(QPainter::Antialiasing);
p.setPen(QPen(Qt::black, 1));
QPointF arrow[3];
arrow[0] = QPointF(img->width()/2, img->height()/2);
arrow[1] = arrow[0] + QPointF(qSin(angle - M_PI/3) * CURENT_SIZE,
qCos(angle - M_PI/3) * CURENT_SIZE);
arrow[2] = arrow[0] + QPointF(qSin(angle - M_PI + M_PI/3) * CURENT_SIZE,
qCos(angle - M_PI + M_PI/3) * CURENT_SIZE);
QLineF l(arrow[1], arrow[2]);
QPointF pt(l.pointAt(0.5));
QLineF l2(arrow[0], pt);
p.translate(arrow[0] - pt);
p.drawPolyline(QPolygonF() << arrow[1] << arrow[0] << arrow[2]);
p.drawLine(arrow[0], l2.pointAt(2));
return img;
}
static QImage *image(uint type, const QVariant &param)
{
if (type>>16 == RDOCAL || type>>16 == I_RDOCAL)
return rdocalArrow(deg2rad(90 - param.toDouble()));
else if (type>>16 == CURENT)
return currentArrow(deg2rad(90 - param.toDouble()));
else
return 0;
return (bt == RDOCAL || bt == I_RDOCAL || bt == CURENT)
? 90 + param.toDouble() : NAN;
}
static bool showLabel(const QImage *img, const Range &range, int zoom, int type)
@ -186,9 +127,10 @@ QPainterPath RasterTile::painterPath(const Polygon &polygon) const
for (int i = 0; i < polygon.size(); i++) {
const QVector<Coordinates> &subpath = polygon.at(i);
path.moveTo(ll2xy(subpath.first()));
for (int j = 1; j < subpath.size(); j++)
path.lineTo(ll2xy(subpath.at(j)));
QVector<QPointF> p(subpath.size());
for (int j = 0; j < subpath.size(); j++)
p[j] = ll2xy(subpath.at(j));
path.addPolygon(p);
}
return path;
@ -352,20 +294,19 @@ void RasterTile::processPoints(QList<MapData::Point*> &points,
const Style::Point &style = s.point(point->type());
const QString *label = point->label().isEmpty() ? 0 : &(point->label());
QImage *rimg = style.img().isNull()
? image(point->type(), point->param()) : 0;
const QImage *img = style.img().isNull() ? rimg : &style.img();
const QImage *img = style.img().isNull() ? 0 : &style.img();
const QFont *fnt = showLabel(img, _data->zooms(), _zoom, point->type())
? font(style.textFontSize()) : 0;
const QColor *color = &style.textColor();
const QColor *hColor = style.haloColor().isValid()
? &style.haloColor() : 0;
double rotate = angle(point->type(), point->param());
if ((!label || !fnt) && !img)
continue;
PointItem *item = new PointItem(pos, label, fnt, img, rimg, color,
hColor);
TextPointItem *item = new TextPointItem(pos, label, fnt, img, color,
hColor, 0, 2, rotate);
if (item->isValid() && !item->collides(textItems)) {
textItems.append(item);
if (lightsMap.contains(point->pos()))

View File

@ -28,19 +28,6 @@ public:
void render();
private:
class PointItem : public TextPointItem
{
public:
PointItem(const QPoint &point, const QString *text, const QFont *font,
const QImage *img, const QImage *rimg, const QColor *color,
const QColor *haloColor) : TextPointItem(point, text, font, img, color,
haloColor, 0, 2), _rimg(rimg) {}
~PointItem() {delete _rimg;}
private:
const QImage *_rimg;
};
void fetchData(QList<MapData::Poly*> &polygons, QList<MapData::Line*> &lines,
QList<MapData::Point*> &points);
QPointF ll2xy(const Coordinates &c) const

View File

@ -248,6 +248,7 @@ void Style::pointStyle()
_points[SUBTYPE(I_DISMAR, 3)] = _points[SUBTYPE(I_DISMAR, 2)];
_points[SUBTYPE(I_DISMAR, 4)] = _points[SUBTYPE(I_DISMAR, 2)];
_points[TYPE(CGUSTA)] = Point(QImage(":/marine/coast-guard.png"));
_points[TYPE(RSCSTA)] = Point(QImage(":/marine/rescue-station.png"));
_points[TYPE(RDOSTA)] = Point(QImage(":/marine/radio.png"));
_points[TYPE(RADSTA)] = Point(QImage(":/marine/radar.png"));
_points[TYPE(RTPBCN)] = Point(QImage(":/marine/radar-transponder.png"));
@ -255,7 +256,9 @@ void Style::pointStyle()
_points[TYPE(I_TRNBSN)] = Point(QImage(":/marine/turning-basin.png"));
_points[TYPE(I_TRNBSN)].setTextColor(QColor("#eb49eb"));
_points[TYPE(I_WTWGAG)] = Point(QImage(":/marine/gauge.png"), Small);
_points[TYPE(RDOCAL)] = Point(QImage(":/marine/radio-call.png"));
_points[TYPE(RDOCAL)].setTextColor(QColor("#eb49eb"));
_points[TYPE(I_RDOCAL)] = Point(QImage(":/marine/radio-call.png"));
_points[TYPE(I_RDOCAL)].setTextColor(QColor("#eb49eb"));
_points[TYPE(PYLONS)] = Point(QImage(":/marine/pylon.png"));
_points[SUBTYPE(I_BERTHS, 6)] = Point(QImage(":/marine/fleeting-area.png"));
@ -265,6 +268,7 @@ void Style::pointStyle()
_points[TYPE(PILBOP)] = Point(QImage(":/marine/boarding-place.png"));
_points[TYPE(SISTAT)] = Point(QImage(":/marine/pylon.png"));
_points[TYPE(SLCONS)] = Point(QImage(":/marine/construction.png"), Small);
_points[TYPE(CURENT)] = Point(QImage(":/marine/current.png"));
_points[SUBTYPE(SMCFAC, 7)] = Point(QImage(":/POI/restaurant-11.png"), Small);
_points[SUBTYPE(SMCFAC, 11)] = Point(QImage(":/POI/pharmacy-11.png"), Small);

View File

@ -25,6 +25,8 @@ class MapData
{
public:
struct Poly {
Poly() : oneway(false) {}
/* QPointF insted of Coordinates for performance reasons (no need to
duplicate all the vectors for drawing). Note, that we do not want to
ll2xy() the points in the MapData class as this can not be done in
@ -34,6 +36,7 @@ public:
Raster raster;
quint32 type;
RectC boundingRect;
bool oneway;
bool operator<(const Poly &other) const
{return type > other.type;}

View File

@ -479,6 +479,8 @@ bool NETFile::link(const SubDiv *subdiv, quint32 shift, Handle &hdl,
if (lbl)
linkLabel(hdl, linkOffset, lbl, lblHdl, poly.label);
if ((linkInfo.flags >> 3) & 1)
poly.oneway = true;
lines->append(poly);

View File

@ -18,6 +18,9 @@ using namespace IMG;
#define AREA(rect) \
(rect.size().width() * rect.size().height())
#define ROAD 0
#define WATER 1
static const QColor textColor(Qt::black);
static const QColor haloColor(Qt::white);
static const QColor shieldColor(Qt::white);
@ -302,17 +305,17 @@ void RasterTile::processPolygons(const QList<MapData::Poly> &polygons,
}
void RasterTile::processLines(QList<MapData::Poly> &lines,
QList<TextItem*> &textItems)
QList<TextItem*> &textItems, const QImage (&arrows)[2])
{
std::stable_sort(lines.begin(), lines.end());
if (_zoom >= 22)
processStreetNames(lines, textItems);
processStreetNames(lines, textItems, arrows);
processShields(lines, textItems);
}
void RasterTile::processStreetNames(const QList<MapData::Poly> &lines,
QList<TextItem*> &textItems)
QList<TextItem*> &textItems, const QImage (&arrows)[2])
{
for (int i = 0; i < lines.size(); i++) {
const MapData::Poly &poly = lines.at(i);
@ -320,21 +323,36 @@ void RasterTile::processStreetNames(const QList<MapData::Poly> &lines,
if (style.img().isNull() && style.foreground() == Qt::NoPen)
continue;
if (poly.label.text().isEmpty()
|| style.textFontSize() == Style::None)
continue;
const QFont *fnt = font(style.textFontSize(), Style::Small);
const QColor *color = style.textColor().isValid()
? &style.textColor() : 0;
const QColor *hColor = Style::isContourLine(poly.type) ? 0 : &haloColor;
const QImage *img = poly.oneway
? Style::isWaterLine(poly.type)
? &arrows[WATER] : &arrows[ROAD] : 0;
const QString *label = poly.label.text().isEmpty()
? 0 : &poly.label.text();
TextPathItem *item = new TextPathItem(poly.points,
&poly.label.text(), _rect, fnt, color, Style::isContourLine(poly.type)
? 0 : &haloColor);
if (!img && (!label || !fnt))
continue;
TextPathItem *item = new TextPathItem(poly.points, label, _rect, fnt,
color, hColor, img);
if (item->isValid() && !item->collides(textItems))
textItems.append(item);
else
else {
delete item;
if (img) {
TextPathItem *item = new TextPathItem(poly.points, 0, _rect, 0,
0, 0, img);
if (item->isValid() && !item->collides(textItems))
textItems.append(item);
else
delete item;
}
}
}
}
@ -462,6 +480,12 @@ void RasterTile::render()
QList<MapData::Poly> lines;
QList<MapData::Point> points;
QList<TextItem*> textItems;
QImage arrows[2];
arrows[ROAD] = (_ratio >= 2)
? QImage(":/map/arrow@2x.png") : QImage(":/map/arrow.png");
arrows[WATER] = (_ratio >= 2)
? QImage(":/map/water-arrow@2x.png") : QImage(":/map/water-arrow.png");
fetchData(polygons, lines, points);
ll2xy(polygons);
@ -470,7 +494,7 @@ void RasterTile::render()
processPoints(points, textItems);
processPolygons(polygons, textItems);
processLines(lines, textItems);
processLines(lines, textItems, arrows);
_pixmap.setDevicePixelRatio(_ratio);
_pixmap.fill(Qt::transparent);
@ -490,5 +514,5 @@ void RasterTile::render()
//painter.setPen(Qt::red);
//painter.setRenderHint(QPainter::Antialiasing, false);
//painter.drawRect(QRect(_xy, _pixmap.size()));
//painter.drawRect(_rect);
}

View File

@ -44,14 +44,14 @@ private:
void processPolygons(const QList<MapData::Poly> &polygons,
QList<TextItem *> &textItems);
void processLines(QList<MapData::Poly> &lines,
QList<TextItem*> &textItems);
void processLines(QList<MapData::Poly> &lines, QList<TextItem*> &textItems,
const QImage (&arrows)[2]);
void processPoints(QList<MapData::Point> &points,
QList<TextItem*> &textItems);
void processShields(const QList<MapData::Poly> &lines,
QList<TextItem*> &textItems);
void processStreetNames(const QList<MapData::Poly> &lines,
QList<TextItem*> &textItems);
QList<TextItem*> &textItems, const QImage (&arrows)[2]);
Projection _proj;
Transform _transform;

View File

@ -292,6 +292,8 @@ bool RGNFile::polyObjects(Handle &hdl, const SubDiv *subdiv,
poly.type = (segmentType == Polygon)
? ((quint32)(type & 0x7F)) << 8 : ((quint32)(type & 0x3F)) << 8;
if (segmentType == Line && type & 0x40)
poly.oneway = true;
QPoint pos(subdiv->lon() + LS(lon, 24-subdiv->bits()),

View File

@ -104,6 +104,9 @@ public:
static bool isWaterArea(quint32 type)
{return ((type >= TYPE(0x3c) && type <= TYPE(0x44))
|| (type & 0xffff00) == TYPE(0x10b));}
static bool isWaterLine(quint32 type)
{return (type == TYPE(0x26) || type == TYPE(0x18)
|| type == TYPE(0x1f));}
static bool isMilitaryArea(quint32 type)
{return (type == TYPE(0x04) || type == 0x10901);}
static bool isNatureReserve(quint32 type)

View File

@ -23,17 +23,21 @@ using namespace Mapsforge;
static void copyPaths(const RectC &rect, const QList<MapData::Path> *src,
QList<MapData::Path> *dst)
{
for (int i = 0; i < src->size(); i++)
if (rect.intersects(src->at(i).poly.boundingRect()))
dst->append(src->at(i));
for (int i = 0; i < src->size(); i++) {
const MapData::Path &path = src->at(i);
if (rect.intersects(path.poly.boundingRect()))
dst->append(path);
}
}
static void copyPoints(const RectC &rect, const QList<MapData::Point> *src,
QList<MapData::Point> *dst)
{
for (int i = 0; i < src->size(); i++)
if (rect.contains(src->at(i).coordinates))
dst->append(src->at(i));
for (int i = 0; i < src->size(); i++) {
const MapData::Point &point = src->at(i);
if (rect.contains(point.coordinates))
dst->append(point);
}
}
static double distance(const Coordinates &c1, const Coordinates &c2)
@ -540,19 +544,20 @@ void MapData::points(const VectorTile *tile, const RectC &rect, int zoom,
_pointLock.unlock();
}
void MapData::paths(const RectC &rect, int zoom, QList<Path> *list)
void MapData::paths(const RectC &searchRect, const RectC &boundsRect, int zoom,
QList<Path> *list)
{
if (!rect.isValid())
if (!searchRect.isValid())
return;
int l(level(zoom));
PathCTX ctx(this, rect, zoom, list);
PathCTX ctx(this, boundsRect, zoom, list);
double min[2], max[2];
min[0] = rect.left();
min[1] = rect.bottom();
max[0] = rect.right();
max[1] = rect.top();
min[0] = searchRect.left();
min[1] = searchRect.bottom();
max[0] = searchRect.right();
max[1] = searchRect.top();
_tiles.at(l)->Search(min, max, pathCb, &ctx);
}

View File

@ -62,7 +62,8 @@ public:
int tileSize() const {return _tileSize;}
void points(const RectC &rect, int zoom, QList<Point> *list);
void paths(const RectC &rect, int zoom, QList<Path> *set);
void paths(const RectC &searchRect, const RectC &boundsRect, int zoom,
QList<Path> *set);
unsigned tagId(const QByteArray &name) const {return _keys.value(name);}
void load();

View File

@ -1,12 +1,16 @@
#include <cmath>
#include <QPainter>
#include <QCache>
#include "common/programpaths.h"
#include "map/rectd.h"
#include "rastertile.h"
using namespace Mapsforge;
#define TEXT_EXTENT 160
#define PATHS_EXTENT 20
#define SEARCH_EXTENT -0.5
static double limit = cos(deg2rad(170));
static qreal area(const QPainterPath &polygon)
{
@ -55,45 +59,89 @@ static const QColor *haloColor(const Style::TextRender *ti)
? &ti->strokeColor() : 0;
}
static QPainterPath parallelPath(const QPainterPath &p, double dy)
{
int n = p.elementCount() - 1;
QVector<QPointF> u(n);
QPainterPath h;
#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
h.reserve(p.elementCount());
#endif // QT 5.13
for (int k = 0; k < n; k++) {
qreal c = p.elementAt(k + 1).x - p.elementAt(k).x;
qreal s = p.elementAt(k + 1).y - p.elementAt(k).y;
qreal l = sqrt(c * c + s * s);
u[k] = (l == 0) ? QPointF(0, 0) : QPointF(c / l, s / l);
if (k == 0)
continue;
if (u.at(k).x() * u.at(k-1).x() + u.at(k).y() * u.at(k-1).y() < limit)
return p;
}
h.moveTo(QPointF(p.elementAt(0).x - dy * u.at(0).y(),
p.elementAt(0).y + dy * u.at(0).x()));
for (int k = 1; k < n; k++) {
qreal l = dy / (1 + u.at(k).x() * u.at(k-1).x()
+ u.at(k).y() * u.at(k-1).y());
QPainterPath::Element e(p.elementAt(k));
h.lineTo(QPointF(e.x - l * (u.at(k).y() + u.at(k-1).y()),
e.y + l * (u.at(k).x() + u.at(k-1).x())));
}
h.lineTo(QPointF(p.elementAt(n).x - dy * u.at(n-1).y(),
p.elementAt(n).y + dy * u.at(n-1).x()));
return h;
}
void RasterTile::processPointLabels(const QList<MapData::Point> &points,
QList<TextItem*> &textItems)
QList<TextItem*> &textItems) const
{
QList<const Style::TextRender*> labels(_style->pointLabels(_zoom));
QList<const Style::Symbol*> symbols(_style->pointSymbols(_zoom));
QList<PainterPoint> painterPoints;
QList<PointText> items;
for (int i = 0; i < points.size(); i++) {
const MapData::Point &point = points.at(i);
const QByteArray *lbl = 0;
const Style::TextRender *ti = 0;
const Style::Symbol *si = 0;
const QByteArray *lbl = 0;
for (int j = 0; j < symbols.size(); j++) {
const Style::Symbol *ri = symbols.at(j);
if (ri->rule().match(point.tags))
if (!si || si->priority() < ri->priority())
si = ri;
}
for (int j = 0; j < labels.size(); j++) {
const Style::TextRender *ri = labels.at(j);
if (ri->rule().match(point.tags)) {
if ((lbl = label(ri->key(), point.tags))) {
if (si && si->id() != ri->symbolId())
continue;
ti = ri;
break;
}
}
}
for (int j = 0; j < symbols.size(); j++) {
const Style::Symbol *ri = symbols.at(j);
if (ri->rule().match(point.tags)) {
si = ri;
break;
}
}
if (ti || si)
painterPoints.append(PainterPoint(&point, lbl, si, ti));
items.append(PointText(&point, lbl, si, ti));
}
std::sort(painterPoints.begin(), painterPoints.end());
std::sort(items.begin(), items.end());
for (int i = 0; i < painterPoints.size(); i++) {
const PainterPoint &p = painterPoints.at(i);
for (int i = 0; i < items.size(); i++) {
const PointText &p = items.at(i);
const QImage *img = p.si ? &p.si->img() : 0;
const QFont *font = p.ti ? &p.ti->font() : 0;
const QColor *color = p.ti ? &p.ti->fillColor() : 0;
@ -108,14 +156,15 @@ void RasterTile::processPointLabels(const QList<MapData::Point> &points,
}
}
void RasterTile::processAreaLabels(QList<TextItem*> &textItems,
QVector<PainterPath> &paths)
void RasterTile::processAreaLabels(const QVector<PainterPath> &paths,
QList<TextItem*> &textItems) const
{
QList<const Style::TextRender*> labels(_style->areaLabels(_zoom));
QList<const Style::Symbol*> symbols(_style->areaSymbols(_zoom));
QList<PathText> items;
for (int i = 0; i < paths.size(); i++) {
PainterPath &path = paths[i];
const PainterPath &path = paths.at(i);
const Style::TextRender *ti = 0;
const Style::Symbol *si = 0;
const QByteArray *lbl = 0;
@ -123,6 +172,69 @@ void RasterTile::processAreaLabels(QList<TextItem*> &textItems,
if (!path.path->closed)
continue;
for (int j = 0; j < symbols.size(); j++) {
const Style::Symbol *ri = symbols.at(j);
if (ri->rule().match(path.path->closed, path.path->tags))
if (!si || si->priority() < ri->priority())
si = ri;
}
for (int j = 0; j < labels.size(); j++) {
const Style::TextRender *ri = labels.at(j);
if (ri->rule().match(path.path->closed, path.path->tags)) {
if ((lbl = label(ri->key(), path.path->tags))) {
if (si && si->id() != ri->symbolId())
continue;
ti = ri;
break;
}
}
}
if (ti || si)
items.append(PathText(&path, lbl, si, ti));
}
std::sort(items.begin(), items.end());
for (int i = 0; i < items.size(); i++) {
const PathText &p = items.at(i);
const QImage *img = p.si ? &p.si->img() : 0;
const QFont *font = p.ti ? &p.ti->font() : 0;
const QColor *color = p.ti ? &p.ti->fillColor() : 0;
const QColor *hColor = p.ti ? haloColor(p.ti) : 0;
QPointF pos = p.p->path->labelPos.isNull()
? centroid(p.p->pp) : ll2xy(p.p->path->labelPos);
PointItem *item = new PointItem(pos.toPoint(), p.lbl, font, img, color,
hColor);
if (item->isValid() && _rect.contains(item->boundingRect().toRect())
&& !item->collides(textItems))
textItems.append(item);
else
delete item;
}
}
void RasterTile::processLineLabels(const QVector<PainterPath> &paths,
QList<TextItem*> &textItems) const
{
QList<const Style::TextRender*> labels(_style->pathLabels(_zoom));
QList<const Style::Symbol*> symbols(_style->lineSymbols(_zoom));
QList<PathText> items;
QSet<QByteArray> set;
for (int i = 0; i < paths.size(); i++) {
const PainterPath &path = paths.at(i);
const Style::TextRender *ti = 0;
const Style::Symbol *si = 0;
const QByteArray *lbl = 0;
if (path.path->closed)
continue;
for (int j = 0; j < labels.size(); j++) {
const Style::TextRender *ri = labels.at(j);
if (ri->rule().match(path.path->closed, path.path->tags)) {
@ -134,61 +246,50 @@ void RasterTile::processAreaLabels(QList<TextItem*> &textItems,
for (int j = 0; j < symbols.size(); j++) {
const Style::Symbol *ri = symbols.at(j);
if (ri->rule().match(path.path->tags)) {
if (ri->rule().match(path.path->closed, path.path->tags)) {
si = ri;
break;
}
}
if (!ti && !si)
continue;
const QImage *img = si ? &si->img() : 0;
const QFont *font = ti ? &ti->font() : 0;
const QColor *color = ti ? &ti->fillColor() : 0;
const QColor *hColor = ti ? haloColor(ti) : 0;
QPointF pos = path.path->labelPos.isNull()
? centroid(path.pp) : ll2xy(path.path->labelPos);
PointItem *item = new PointItem(pos.toPoint(), lbl, font, img, color,
hColor);
if (item->isValid() && _rect.contains(item->boundingRect().toRect())
&& !item->collides(textItems))
textItems.append(item);
else
delete item;
if (ti || si)
items.append(PathText(&path, lbl, si, ti));
}
}
void RasterTile::processLineLabels(QList<TextItem*> &textItems,
QVector<PainterPath> &paths)
{
QList<const Style::TextRender*> instructions(_style->pathLabels(_zoom));
QSet<QByteArray> set;
std::sort(items.begin(), items.end());
for (int i = 0; i < instructions.size(); i++) {
const Style::TextRender *ri = instructions.at(i);
for (int i = 0; i < items.size(); i++) {
const PathText &p = items.at(i);
const QImage *img = p.si ? &p.si->img() : 0;
const QFont *font = p.ti ? &p.ti->font() : 0;
const QColor *color = p.ti ? &p.ti->fillColor() : 0;
const QColor *hColor = p.ti ? haloColor(p.ti) : 0;
bool rotate = p.si ? p.si->rotate() : false;
bool limit = false;
for (int i = 0; i < paths.size(); i++) {
PainterPath &path = paths[i];
const QByteArray *lbl = label(ri->key(), path.path->tags);
if (!lbl)
continue;
if (!ri->rule().match(path.path->closed, path.path->tags))
continue;
bool limit = (ri->key() == ID_ELE || ri->key() == ID_REF);
if (limit && set.contains(*lbl))
if (p.ti) {
limit = (p.ti->key() == ID_ELE || p.ti->key() == ID_REF);
if (limit && set.contains(*p.lbl))
continue;
}
PathItem *item = new PathItem(path.pp, lbl, _rect, &ri->font(),
&ri->fillColor(), haloColor(ri));
if (item->isValid() && !item->collides(textItems)) {
textItems.append(item);
if (limit)
set.insert(*lbl);
} else
delete item;
PathItem *item = new PathItem(p.p->pp, p.lbl, img, _rect, font, color,
hColor, rotate);
if (item->isValid() && !item->collides(textItems)) {
textItems.append(item);
if (limit)
set.insert(*p.lbl);
} else {
delete item;
if (img && p.lbl) {
PathItem *item = new PathItem(p.p->pp, 0, img, _rect, 0, 0, 0,
rotate);
if (item->isValid() && !item->collides(textItems))
textItems.append(item);
else
delete item;
}
}
}
}
@ -244,7 +345,7 @@ QPainterPath RasterTile::painterPath(const Polygon &polygon, bool curve) const
void RasterTile::pathInstructions(const QList<MapData::Path> &paths,
QVector<PainterPath> &painterPaths,
QVector<RasterTile::RenderInstruction> &instructions)
QVector<RasterTile::RenderInstruction> &instructions) const
{
QCache<PathKey, QList<const Style::PathRender *> > cache(8192);
QList<const Style::PathRender*> *ri;
@ -270,7 +371,7 @@ void RasterTile::pathInstructions(const QList<MapData::Path> &paths,
}
void RasterTile::circleInstructions(const QList<MapData::Point> &points,
QVector<RasterTile::RenderInstruction> &instructions)
QVector<RasterTile::RenderInstruction> &instructions) const
{
QCache<PointKey, QList<const Style::CircleRender *> > cache(8192);
QList<const Style::CircleRender*> *ri;
@ -306,13 +407,18 @@ void RasterTile::drawPaths(QPainter *painter, const QList<MapData::Path> &paths,
if (path) {
const Style::PathRender *ri = is.pathRender();
qreal dy = ri->dy(_zoom);
if (!path->pp.elementCount())
path->pp = painterPath(path->path->poly, ri->curve());
painter->setPen(ri->pen(_zoom));
painter->setBrush(ri->brush());
painter->drawPath(path->pp);
if (dy != 0)
painter->drawPath(parallelPath(path->pp, dy));
else
painter->drawPath(path->pp);
} else {
const Style::CircleRender *ri = is.circleRender();
qreal radius = ri->radius(_zoom);
@ -325,18 +431,22 @@ void RasterTile::drawPaths(QPainter *painter, const QList<MapData::Path> &paths,
}
void RasterTile::fetchData(QList<MapData::Path> &paths,
QList<MapData::Point> &points)
QList<MapData::Point> &points) const
{
QPoint ttl(_rect.topLeft());
/* Add a "sub-pixel" margin to assure the tile areas do not
overlap on the border lines. This prevents areas overlap
artifacts at least when using the EPSG:3857 projection. */
QRectF pathRect(QPointF(ttl.x() + 0.5, ttl.y() + 0.5),
QPointF(ttl.x() + _rect.width() - 0.5, ttl.y() + _rect.height() - 0.5));
QRectF pathRect(QPointF(ttl.x() - PATHS_EXTENT, ttl.y() - PATHS_EXTENT),
QPointF(ttl.x() + _rect.width() + PATHS_EXTENT, ttl.y() + _rect.height()
+ PATHS_EXTENT));
QRectF searchRect(QPointF(ttl.x() - SEARCH_EXTENT, ttl.y() - SEARCH_EXTENT),
QPointF(ttl.x() + _rect.width() + SEARCH_EXTENT, ttl.y() + _rect.height()
+ SEARCH_EXTENT));
RectD pathRectD(_transform.img2proj(pathRect.topLeft()),
_transform.img2proj(pathRect.bottomRight()));
_data->paths(pathRectD.toRectC(_proj, 20), _zoom, &paths);
RectD searchRectD(_transform.img2proj(searchRect.topLeft()),
_transform.img2proj(searchRect.bottomRight()));
_data->paths(searchRectD.toRectC(_proj, 20), pathRectD.toRectC(_proj, 20),
_zoom, &paths);
QRectF pointRect(QPointF(ttl.x() - TEXT_EXTENT, ttl.y() - TEXT_EXTENT),
QPointF(ttl.x() + _rect.width() + TEXT_EXTENT, ttl.y() + _rect.height()
@ -361,18 +471,20 @@ void RasterTile::render()
QPainter painter(&_pixmap);
painter.setRenderHint(QPainter::Antialiasing);
painter.setRenderHint(QPainter::SmoothPixmapTransform);
painter.translate(-_rect.x(), -_rect.y());
drawPaths(&painter, paths, points, renderPaths);
processPointLabels(points, textItems);
processAreaLabels(textItems, renderPaths);
processLineLabels(textItems, renderPaths);
processAreaLabels(renderPaths, textItems);
processLineLabels(renderPaths, textItems);
drawTextItems(&painter, textItems);
//painter.setPen(Qt::red);
//painter.setBrush(Qt::NoBrush);
//painter.drawRect(QRect(_rect.topLeft(), _pixmap.size()));
//painter.setRenderHint(QPainter::Antialiasing, false);
//painter.drawRect(_rect);
qDeleteAll(textItems);

View File

@ -14,13 +14,16 @@ namespace Mapsforge {
class RasterTile
{
public:
/* Mapsforge maps zoom levels are offset by one against the standard OSM
zoom levels! We decrease the zoom level internaly here when initializing
_zoom and return the propper/increased value back in zoom() */
RasterTile(const Projection &proj, const Transform &transform,
const Style *style, MapData *data, int zoom, const QRect &rect,
qreal ratio) : _proj(proj), _transform(transform), _style(style),
_data(data), _zoom(zoom), _rect(rect), _ratio(ratio),
_data(data), _zoom(zoom - 1), _rect(rect), _ratio(ratio),
_pixmap(rect.width() * ratio, rect.height() * ratio), _valid(false) {}
int zoom() const {return _zoom;}
int zoom() const {return _zoom + 1;}
QPoint xy() const {return _rect.topLeft();}
const QPixmap &pixmap() const {return _pixmap;}
bool isValid() const {return _valid;}
@ -35,15 +38,15 @@ private:
const MapData::Path *path;
};
struct PainterPoint {
PainterPoint(const MapData::Point *p, const QByteArray *lbl,
struct PointText {
PointText(const MapData::Point *p, const QByteArray *lbl,
const Style::Symbol *si, const Style::TextRender *ti)
: p(p), lbl(lbl), ti(ti), si(si)
{
Q_ASSERT(si || ti);
}
bool operator<(const PainterPoint &other) const
bool operator<(const PointText &other) const
{
if (priority() == other.priority())
return p->id < other.p->id;
@ -58,6 +61,26 @@ private:
const Style::Symbol *si;
};
struct PathText {
PathText(const PainterPath *p, const QByteArray *lbl,
const Style::Symbol *si, const Style::TextRender *ti)
: p(p), lbl(lbl), ti(ti), si(si)
{
Q_ASSERT(si || ti);
}
bool operator<(const PathText &other) const
{
return (priority() > other.priority());
}
int priority() const {return si ? si->priority() : ti->priority();}
const PainterPath *p;
const QByteArray *lbl;
const Style::TextRender *ti;
const Style::Symbol *si;
};
class RenderInstruction
{
public:
@ -137,29 +160,31 @@ private:
{
public:
PathItem(const QPainterPath &line, const QByteArray *label,
const QRect &tileRect, const QFont *font, const QColor *color,
const QColor *haloColor) : TextPathItem(line,
label ? new QString(*label) : 0, tileRect, font, color, haloColor) {}
const QImage *img, const QRect &tileRect, const QFont *font,
const QColor *color, const QColor *haloColor, bool rotate)
: TextPathItem(line, label ? new QString(*label) : 0, tileRect, font,
color, haloColor, img, rotate) {}
~PathItem() {delete _text;}
};
friend HASH_T qHash(const RasterTile::PathKey &key);
friend HASH_T qHash(const RasterTile::PointKey &key);
void fetchData(QList<MapData::Path> &paths, QList<MapData::Point> &points);
void fetchData(QList<MapData::Path> &paths,
QList<MapData::Point> &points) const;
void pathInstructions(const QList<MapData::Path> &paths,
QVector<PainterPath> &painterPaths,
QVector<RasterTile::RenderInstruction> &instructions);
QVector<RasterTile::RenderInstruction> &instructions) const;
void circleInstructions(const QList<MapData::Point> &points,
QVector<RasterTile::RenderInstruction> &instructions);
QVector<RasterTile::RenderInstruction> &instructions) const;
QPointF ll2xy(const Coordinates &c) const
{return _transform.proj2img(_proj.ll2xy(c));}
void processPointLabels(const QList<MapData::Point> &points,
QList<TextItem*> &textItems);
void processAreaLabels(QList<TextItem*> &textItems,
QVector<PainterPath> &paths);
void processLineLabels(QList<TextItem*> &textItems,
QVector<PainterPath> &paths);
QList<TextItem*> &textItems) const;
void processAreaLabels(const QVector<PainterPath> &paths,
QList<TextItem*> &textItems) const;
void processLineLabels(const QVector<PainterPath> &paths,
QList<TextItem*> &textItems) const;
QPainterPath painterPath(const Polygon &polygon, bool curve) const;
void drawTextItems(QPainter *painter, const QList<TextItem*> &textItems);
void drawPaths(QPainter *painter, const QList<MapData::Path> &paths,

View File

@ -17,18 +17,26 @@ static QString resourcePath(const QString &src, const QString &dir)
return dir + "/" + url.toLocalFile();
}
static QImage image(const QString &path, int width, int height, qreal ratio)
static QImage image(const QString &path, int width, int height, int percent,
qreal ratio)
{
QImageReader ir(path, "svg");
if (ir.canRead()) {
QSize s(ir.size());
if (!height && !width) {
height = 20;
width = 20;
} else if (!width) {
width = ir.size().height() / (ir.size().height() / (double)height);
width = s.height() / (s.height() / (double)height);
} else if (!height)
height = ir.size().width() / (ir.size().width() / (double)width);
height = s.width() / (s.width() / (double)width);
if (percent != 100) {
width *= percent / 100.0;
height *= percent / 100.0;
}
ir.setScaledSize(QSize(width * ratio, height * ratio));
QImage img(ir.read());
@ -69,6 +77,42 @@ static QList<QByteArray> valList(const QList<QByteArray> &in)
return out;
}
const Style::Menu::Layer *Style::Menu::findLayer(const QString &id) const
{
for (int i = 0; i < _layers.size(); i++)
if (_layers.at(i).id() == id)
return &_layers.at(i);
qWarning("%s: layer not found", qPrintable(id));
return 0;
}
void Style::Menu::addCats(const Layer *layer, QSet<QString> &cats) const
{
if (!layer)
return;
if (!layer->parent().isNull())
addCats(findLayer(layer->parent()), cats);
for (int i = 0; i < layer->cats().size(); i++)
cats.insert(layer->cats().at(i));
for (int i = 0; i < layer->overlays().size(); i++) {
const Layer *overlay = findLayer(layer->overlays().at(i));
if (overlay && overlay->enabled())
addCats(overlay, cats);
}
}
QSet<QString> Style::Menu::cats() const
{
QSet<QString> c;
addCats(findLayer(_defaultvalue), c);
return c;
}
Style::Rule::Filter::Filter(const MapData &data, const QList<QByteArray> &keys,
const QList<QByteArray> &vals) : _neg(false)
{
@ -139,7 +183,7 @@ void Style::area(QXmlStreamReader &reader, const QString &dir, qreal ratio,
const QXmlStreamAttributes &attr = reader.attributes();
QString file;
QColor fillColor;
int height = 0, width = 0;
int height = 0, width = 0, percent = 100;
bool ok;
ri._area = true;
@ -177,9 +221,16 @@ void Style::area(QXmlStreamReader &reader, const QString &dir, qreal ratio,
return;
}
}
if (attr.hasAttribute("symbol-percent")) {
percent = attr.value("symbol-percent").toInt(&ok);
if (!ok || percent < 0) {
reader.raiseError("invalid symbol-percent value");
return;
}
}
if (!file.isNull())
ri._brush = QBrush(image(file, width, height, ratio));
ri._brush = QBrush(image(file, width, height, percent, ratio));
else if (fillColor.isValid())
ri._brush = QBrush(fillColor);
@ -195,6 +246,8 @@ void Style::line(QXmlStreamReader &reader, const Rule &rule)
const QXmlStreamAttributes &attr = reader.attributes();
bool ok;
ri._brush = Qt::NoBrush;
if (attr.hasAttribute("stroke"))
ri._strokeColor = QColor(attr.value("stroke").toString());
if (attr.hasAttribute("stroke-width")) {
@ -245,6 +298,13 @@ void Style::line(QXmlStreamReader &reader, const Rule &rule)
if (curve == "cubic")
ri._curve = true;
}
if (attr.hasAttribute("dy")) {
ri._dy = attr.value("dy").toDouble(&ok);
if (!ok) {
reader.raiseError("invalid dy value");
return;
}
}
if (ri.rule()._type == Rule::AnyType || ri.rule()._type == Rule::WayType)
_paths.append(ri);
@ -361,6 +421,8 @@ void Style::text(QXmlStreamReader &reader, const MapData &data, const Rule &rule
return;
}
}
if (attr.hasAttribute("symbol-id"))
ri._symbolId = attr.value("symbol-id").toString();
ri._font.setFamily(fontFamily);
ri._font.setPixelSize(fontSize);
@ -376,12 +438,12 @@ void Style::text(QXmlStreamReader &reader, const MapData &data, const Rule &rule
}
void Style::symbol(QXmlStreamReader &reader, const QString &dir, qreal ratio,
const Rule &rule)
const Rule &rule, QList<Symbol> &list)
{
Symbol ri(rule);
const QXmlStreamAttributes &attr = reader.attributes();
QString file;
int height = 0, width = 0;
int height = 0, width = 0, percent = 100;
bool ok;
if (attr.hasAttribute("src"))
@ -404,6 +466,13 @@ void Style::symbol(QXmlStreamReader &reader, const QString &dir, qreal ratio,
return;
}
}
if (attr.hasAttribute("symbol-percent")) {
percent = attr.value("symbol-percent").toInt(&ok);
if (!ok || percent < 0) {
reader.raiseError("invalid symbol-percent value");
return;
}
}
if (attr.hasAttribute("priority")) {
ri._priority = attr.value("priority").toInt(&ok);
if (!ok) {
@ -411,10 +480,16 @@ void Style::symbol(QXmlStreamReader &reader, const QString &dir, qreal ratio,
return;
}
}
if (attr.hasAttribute("rotate")) {
if (attr.value("rotate").toString() == "false")
ri._rotate = false;
}
if (attr.hasAttribute("id"))
ri._id = attr.value("id").toString();
ri._img = image(file, width, height, ratio);
ri._img = image(file, width, height, percent, ratio);
_symbols.append(ri);
list.append(ri);
reader.skipCurrentElement();
}
@ -486,42 +561,73 @@ void Style::rule(QXmlStreamReader &reader, const QString &dir,
text(reader, data, r, list);
}
else if (reader.name() == QLatin1String("symbol"))
symbol(reader, dir, ratio, r);
symbol(reader, dir, ratio, r, _symbols);
else if (reader.name() == QLatin1String("lineSymbol"))
symbol(reader, dir, ratio, r, _lineSymbols);
else
reader.skipCurrentElement();
}
}
void Style::cat(QXmlStreamReader &reader, QSet<QString> &cats)
QString Style::cat(QXmlStreamReader &reader)
{
const QXmlStreamAttributes &attr = reader.attributes();
cats.insert(attr.value("id").toString());
if (!attr.hasAttribute("id")) {
reader.raiseError("Missing id attribute");
return QString();
}
QString id(attr.value("id").toString());
reader.skipCurrentElement();
return id;
}
void Style::layer(QXmlStreamReader &reader, QSet<QString> &cats)
Style::Menu::Layer Style::layer(QXmlStreamReader &reader)
{
const QXmlStreamAttributes &attr = reader.attributes();
bool enabled = (attr.value("enabled").toString() == "true");
if (!attr.hasAttribute("id")) {
reader.raiseError("Missing id attribute");
return Menu::Layer();
}
Menu::Layer l(attr.value("id").toString(),
attr.value("enabled").toString() == "true");
if (attr.hasAttribute("parent"))
l.setParent(attr.value("parent").toString());
while (reader.readNextStartElement()) {
if (enabled && reader.name() == QLatin1String("cat"))
cat(reader, cats);
if (reader.name() == QLatin1String("cat"))
l.addCat(cat(reader));
else if (reader.name() == QLatin1String("overlay"))
l.addOverlay(cat(reader));
else
reader.skipCurrentElement();
}
return l;
}
void Style::stylemenu(QXmlStreamReader &reader, QSet<QString> &cats)
Style::Menu Style::stylemenu(QXmlStreamReader &reader)
{
const QXmlStreamAttributes &attr = reader.attributes();
if (!attr.hasAttribute("defaultvalue")) {
reader.raiseError("Missing defaultvalue attribute");
return Menu();
}
Style::Menu menu(attr.value("defaultvalue").toString());
while (reader.readNextStartElement()) {
if (reader.name() == QLatin1String("layer"))
layer(reader, cats);
menu.addLayer(layer(reader));
else
reader.skipCurrentElement();
}
return menu;
}
void Style::rendertheme(QXmlStreamReader &reader, const QString &dir,
@ -533,9 +639,10 @@ void Style::rendertheme(QXmlStreamReader &reader, const QString &dir,
while (reader.readNextStartElement()) {
if (reader.name() == QLatin1String("rule"))
rule(reader, dir, data, ratio, cats, r);
else if (reader.name() == QLatin1String("stylemenu"))
stylemenu(reader, cats);
else
else if (reader.name() == QLatin1String("stylemenu")) {
Menu menu(stylemenu(reader));
cats = menu.cats();
} else
reader.skipCurrentElement();
}
}
@ -643,7 +750,7 @@ QList<const Style::Symbol*> Style::pointSymbols(int zoom) const
for (int i = 0; i < _symbols.size(); i++) {
const Symbol &symbol = _symbols.at(i);
const Rule & rule = symbol.rule();
const Rule &rule = symbol.rule();
if (rule._zooms.contains(zoom) && (rule._type == Rule::AnyType
|| rule._type == Rule::NodeType))
list.append(&symbol);
@ -652,6 +759,19 @@ QList<const Style::Symbol*> Style::pointSymbols(int zoom) const
return list;
}
QList<const Style::Symbol*> Style::lineSymbols(int zoom) const
{
QList<const Symbol*> list;
for (int i = 0; i < _lineSymbols.size(); i++) {
const Symbol &symbol = _lineSymbols.at(i);
if (symbol.rule()._zooms.contains(zoom))
list.append(&symbol);
}
return list;
}
QList<const Style::Symbol*> Style::areaSymbols(int zoom) const
{
QList<const Symbol*> list;
@ -689,6 +809,11 @@ QPen Style::PathRender::pen(int zoom) const
return Qt::NoPen;
}
qreal Style::PathRender::dy(int zoom) const
{
return (_scale && zoom >= 12) ? pow(1.5, zoom - 12) * _dy : _dy;
}
qreal Style::CircleRender::radius(int zoom) const
{
return (_scale && zoom >= 12) ? pow(1.5, zoom - 12) * _radius : _radius;

View File

@ -137,13 +137,14 @@ public:
PathRender(const Rule &rule, int zOrder) : Render(rule),
_zOrder(zOrder), _strokeWidth(0), _strokeCap(Qt::RoundCap),
_strokeJoin(Qt::RoundJoin), _area(false), _curve(false),
_scale(Stroke) {}
_scale(Stroke), _dy(0) {}
int zOrder() const {return _zOrder;}
QPen pen(int zoom) const;
const QBrush &brush() const {return _brush;}
bool area() const {return _area;}
bool curve() const {return _curve;}
qreal dy(int zoom) const;
private:
friend class Style;
@ -159,6 +160,7 @@ public:
QBrush _brush;
bool _area, _curve;
Scale _scale;
qreal _dy;
};
class CircleRender : public Render
@ -190,6 +192,7 @@ public:
: Render(rule), _priority(0), _fillColor(Qt::black),
_strokeColor(Qt::black), _strokeWidth(0) {}
const QString &symbolId() const {return _symbolId;}
const QFont &font() const {return _font;}
const QColor &fillColor() const {return _fillColor;}
const QColor &strokeColor() const {return _strokeColor;}
@ -200,6 +203,7 @@ public:
private:
friend class Style;
QString _symbolId;
int _priority;
QColor _fillColor, _strokeColor;
qreal _strokeWidth;
@ -210,15 +214,20 @@ public:
class Symbol : public Render
{
public:
Symbol(const Rule &rule) : Render(rule), _priority(0) {}
Symbol(const Rule &rule)
: Render(rule), _priority(0), _rotate(true) {}
const QString &id() const {return _id;}
const QImage &img() const {return _img;}
bool rotate() const {return _rotate;}
int priority() const {return _priority;}
private:
friend class Style;
QString _id;
int _priority;
bool _rotate;
QImage _img;
};
@ -234,19 +243,60 @@ public:
QList<const TextRender*> areaLabels(int zoom) const;
QList<const Symbol*> pointSymbols(int zoom) const;
QList<const Symbol*> areaSymbols(int zoom) const;
QList<const Symbol*> lineSymbols(int zoom) const;
private:
class Menu {
public:
class Layer {
public:
Layer() : _enabled(false) {}
Layer(const QString &id, bool enabled)
: _id(id), _enabled(enabled) {}
const QStringList &cats() const {return _cats;}
const QStringList &overlays() const {return _overlays;}
const QString &id() const {return _id;}
const QString &parent() const {return _parent;}
bool enabled() const {return _enabled;}
void setParent(const QString &parent) {_parent = parent;}
void addCat(const QString &cat) {_cats.append(cat);}
void addOverlay(const QString &overlay) {_overlays.append(overlay);}
private:
QStringList _cats;
QStringList _overlays;
QString _id;
QString _parent;
bool _enabled;
};
Menu() {}
Menu(const QString &defaultValue) : _defaultvalue(defaultValue) {}
void addLayer(const Layer &layer) {_layers.append(layer);}
QSet<QString> cats() const;
private:
const Layer *findLayer(const QString &id) const;
void addCats(const Layer *layer, QSet<QString> &cats) const;
QString _defaultvalue;
QList<Layer> _layers;
};
QList<PathRender> _paths;
QList<CircleRender> _circles;
QList<TextRender> _pathLabels, _pointLabels, _areaLabels;
QList<Symbol> _symbols;
QList<Symbol> _symbols, _lineSymbols;
bool loadXml(const QString &path, const MapData &data, qreal ratio);
void rendertheme(QXmlStreamReader &reader, const QString &dir,
const MapData &data, qreal ratio);
void layer(QXmlStreamReader &reader, QSet<QString> &cats);
void stylemenu(QXmlStreamReader &reader, QSet<QString> &cats);
void cat(QXmlStreamReader &reader, QSet<QString> &cats);
Menu::Layer layer(QXmlStreamReader &reader);
Menu stylemenu(QXmlStreamReader &reader);
QString cat(QXmlStreamReader &reader);
void rule(QXmlStreamReader &reader, const QString &dir, const MapData &data,
qreal ratio, const QSet<QString> &cats, const Rule &parent);
void area(QXmlStreamReader &reader, const QString &dir, qreal ratio,
@ -256,7 +306,7 @@ private:
void text(QXmlStreamReader &reader, const MapData &data, const Rule &rule,
QList<QList<TextRender> *> &lists);
void symbol(QXmlStreamReader &reader, const QString &dir, qreal ratio,
const Rule &rule);
const Rule &rule, QList<Symbol> &list);
};
}

View File

@ -167,18 +167,19 @@ void MapsforgeMap::cancelJobs(bool wait)
void MapsforgeMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
{
QPointF tl(floor(rect.left() / _data.tileSize()) * _data.tileSize(),
floor(rect.top() / _data.tileSize()) * _data.tileSize());
int tileSize = (_data.tileSize() < 384)
? _data.tileSize() << 1 : _data.tileSize();
QPointF tl(floor(rect.left() / tileSize) * tileSize,
floor(rect.top() / tileSize) * tileSize);
QSizeF s(rect.right() - tl.x(), rect.bottom() - tl.y());
int width = ceil(s.width() / _data.tileSize());
int height = ceil(s.height() / _data.tileSize());
int width = ceil(s.width() / tileSize);
int height = ceil(s.height() / tileSize);
QList<RasterTile> tiles;
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
QPoint ttl(tl.x() + i * _data.tileSize(), tl.y() + j
* _data.tileSize());
QPoint ttl(tl.x() + i * tileSize, tl.y() + j * tileSize);
if (isRunning(_zoom, ttl))
continue;
@ -187,8 +188,7 @@ void MapsforgeMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
painter->drawPixmap(ttl, pm);
else {
tiles.append(RasterTile(_projection, _transform, &_style, &_data,
_zoom, QRect(ttl, QSize(_data.tileSize(), _data.tileSize())),
_tileRatio));
_zoom, QRect(ttl, QSize(tileSize, tileSize)), _tileRatio));
}
}
}

View File

@ -18,9 +18,8 @@ OnlineMap::OnlineMap(const QString &fileName, const QString &name,
{
_tileLoader = new TileLoader(QDir(ProgramPaths::tilesDir()).filePath(_name),
this);
_tileLoader->setUrl(url);
_tileLoader->setUrl(url, quadTiles ? TileLoader::QuadTiles : TileLoader::XYZ);
_tileLoader->setHeaders(headers);
_tileLoader->setQuadTiles(quadTiles);
connect(_tileLoader, &TileLoader::finished, this, &OnlineMap::tilesLoaded);
}

View File

@ -2,8 +2,9 @@
#include <QPainter>
#include "textpathitem.h"
#define CHAR_RATIO 0.55
#define MAX_TEXT_ANGLE 30
#define PADDING 2
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
#define INTERSECTS intersect
@ -12,6 +13,22 @@
#endif // QT 5.15
static void swap(const QLineF &line, QPointF *p1, QPointF *p2)
{
QPointF lp1(line.p1());
QPointF lp2(line.p2());
if ((lp1.rx() < lp2.rx() && p1->rx() > p2->rx())
|| (lp1.ry() < lp2.ry() && p1->ry() > p2->ry())
|| (lp1.rx() > lp2.rx() && p1->rx() < p2->rx())
|| (lp1.ry() > lp2.ry() && p1->ry() < p2->ry())) {
QPointF tmp(*p2);
*p2 = *p1;
*p1 = tmp;
}
}
static bool intersection(const QLineF &line, const QRectF &rect, QPointF *p)
{
if (line.INTERSECTS(QLineF(rect.topLeft(), rect.topRight()), p)
@ -40,20 +57,26 @@ static bool intersection(const QLineF &line, const QRectF &rect, QPointF *p1,
p = p2;
if (line.INTERSECTS(QLineF(rect.topLeft(), rect.bottomLeft()), p)
== QLineF::BoundedIntersection) {
if (p == p2)
if (p == p2) {
swap(line, p1, p2);
return true;
}
p = p2;
}
if (line.INTERSECTS(QLineF(rect.bottomRight(), rect.bottomLeft()), p)
== QLineF::BoundedIntersection) {
if (p == p2)
if (p == p2) {
swap(line, p1, p2);
return true;
}
p = p2;
}
if (line.INTERSECTS(QLineF(rect.bottomRight(), rect.topRight()), p)
== QLineF::BoundedIntersection) {
if (p == p2)
if (p == p2) {
swap(line, p1, p2);
return true;
}
}
Q_ASSERT(p != p2);
@ -197,6 +220,13 @@ static QList<QLineF> lineString(const QPainterPath &path,
return lines;
}
static bool reverse(const QPainterPath &path)
{
QLineF l(path.elementAt(0), path.elementAt(1));
qreal angle = l.angle();
return (angle > 90 && angle < 270) ? true : false;
}
template<class T>
static QPainterPath textPath(const T &path, qreal textWidth,
qreal charWidth, const QRectF &tileRect)
@ -229,109 +259,132 @@ static QPainterPath textPath(const T &path, qreal textWidth,
: QPainterPath();
}
static bool reverse(const QPainterPath &path)
template<class T>
void TextPathItem::init(const T &line, const QRect &tileRect)
{
QLineF l(path.elementAt(0), path.elementAt(1));
qreal angle = l.angle();
return (angle > 90 && angle < 270) ? true : false;
qreal cw, mw, textWidth;
bool label = _text && _font;
Q_ASSERT(label || _img);
if (label && _img) {
cw = _font->pixelSize() * CHAR_RATIO;
mw = _font->pixelSize() / 2.0;
textWidth = _text->size() * cw + _img->width() + PADDING;
} else if (label) {
cw = _font->pixelSize() * CHAR_RATIO;
mw = _font->pixelSize() / 2.0;
textWidth = _text->size() * cw;
} else {
cw = _img->width();
mw = _img->height() / 2.0;
textWidth = _img->width();
}
_path = textPath(line, textWidth, cw, tileRect.adjusted(mw, mw, -mw, -mw));
if (_path.isEmpty())
return;
if (reverse(_path)) {
_path = _path.toReversed();
_reverse = true;
}
QPainterPathStroker s;
s.setWidth(mw * 2);
s.setCapStyle(Qt::FlatCap);
_shape = s.createStroke(_path).simplified();
_rect = _shape.boundingRect();
}
TextPathItem::TextPathItem(const QPolygonF &line, const QString *label,
const QRect &tileRect, const QFont *font, const QColor *color,
const QColor *haloColor) : TextItem(label), _font(font), _color(color),
_haloColor(haloColor)
const QColor *haloColor, const QImage *img, bool rotate)
: TextItem(label), _font(font), _color(color), _haloColor(haloColor),
_img(img), _rotate(rotate), _reverse(false)
{
qreal cw = font->pixelSize() * 0.6;
qreal textWidth = _text->size() * cw;
qreal mw = font->pixelSize() / 2;
_path = textPath(line, textWidth, cw, tileRect.adjusted(mw, mw, -mw, -mw));
if (_path.isEmpty())
return;
if (reverse(_path))
_path = _path.toReversed();
QPainterPathStroker s;
s.setWidth(font->pixelSize());
s.setCapStyle(Qt::FlatCap);
_shape = s.createStroke(_path).simplified();
_rect = _shape.boundingRect();
init(line, tileRect);
}
TextPathItem::TextPathItem(const QPainterPath &line, const QString *label,
const QRect &tileRect, const QFont *font, const QColor *color,
const QColor *haloColor) : TextItem(label), _font(font), _color(color),
_haloColor(haloColor)
const QColor *haloColor, const QImage *img, bool rotate)
: TextItem(label), _font(font), _color(color), _haloColor(haloColor),
_img(img), _rotate(rotate), _reverse(false)
{
qreal cw = font->pixelSize() * 0.6;
qreal textWidth = _text->size() * cw;
qreal mw = font->pixelSize() / 2;
_path = textPath(line, textWidth, cw, tileRect.adjusted(mw, mw, -mw, -mw));
if (_path.isEmpty())
return;
if (reverse(_path))
_path = _path.toReversed();
QPainterPathStroker s;
s.setWidth(font->pixelSize());
s.setCapStyle(Qt::FlatCap);
_shape = s.createStroke(_path).simplified();
_rect = _shape.boundingRect();
init(line, tileRect);
}
void TextPathItem::paint(QPainter *painter) const
{
QFontMetrics fm(*_font);
int textWidth = fm.boundingRect(*_text).width();
if (_img) {
QSizeF s(_img->size() / _img->devicePixelRatioF());
qreal factor = (textWidth) / qMax(_path.length(), (qreal)textWidth);
qreal percent = (1.0 - factor) / 2.0;
painter->save();
painter->translate(QPointF(_path.elementAt(0).x, _path.elementAt(0).y));
painter->rotate(360 - _path.angleAtPercent(0));
if (_reverse && _rotate) {
painter->rotate(180);
painter->translate(-s.width(), 0);
}
painter->drawImage(QPointF(0, -s.height()/2), *_img);
painter->restore();
}
QTransform t = painter->transform();
if (_text && _font) {
QFontMetrics fm(*_font);
int textWidth = fm.boundingRect(*_text).width();
int imgWidth = _img ? _img->width() + PADDING : 0;
qreal imgPercent = imgWidth / _path.length();
qreal factor = textWidth / qMax(_path.length(), (qreal)(textWidth));
qreal percent = ((1.0 - factor) + imgPercent) / 2.0;
QTransform t = painter->transform();
painter->setFont(*_font);
painter->setFont(*_font);
if (_haloColor) {
painter->setPen(*_haloColor);
if (_haloColor) {
painter->setPen(*_haloColor);
for (int i = 0; i < _text->size(); i++) {
QPointF point = _path.pointAtPercent(percent);
qreal angle = _path.angleAtPercent(percent);
QChar c = _text->at(i);
painter->translate(point);
painter->rotate(-angle);
painter->drawText(QPoint(-1, fm.descent() - 1), c);
painter->drawText(QPoint(1, fm.descent() + 1), c);
painter->drawText(QPoint(-1, fm.descent() + 1), c);
painter->drawText(QPoint(1, fm.descent() -1), c);
painter->drawText(QPoint(0, fm.descent() - 1), c);
painter->drawText(QPoint(0, fm.descent() + 1), c);
painter->drawText(QPoint(-1, fm.descent()), c);
painter->drawText(QPoint(1, fm.descent()), c);
painter->setTransform(t);
int width = fm.horizontalAdvance(_text->at(i));
percent += ((qreal)width / (qreal)textWidth) * factor;
}
percent = ((1.0 - factor) + imgPercent) / 2.0;
}
painter->setPen(_color ? *_color : Qt::black);
for (int i = 0; i < _text->size(); i++) {
QPointF point = _path.pointAtPercent(percent);
qreal angle = _path.angleAtPercent(percent);
QChar c = _text->at(i);
painter->translate(point);
painter->rotate(-angle);
painter->drawText(QPoint(-1, fm.descent() - 1), c);
painter->drawText(QPoint(1, fm.descent() + 1), c);
painter->drawText(QPoint(-1, fm.descent() + 1), c);
painter->drawText(QPoint(1, fm.descent() -1), c);
painter->drawText(QPoint(0, fm.descent() - 1), c);
painter->drawText(QPoint(0, fm.descent() + 1), c);
painter->drawText(QPoint(-1, fm.descent()), c);
painter->drawText(QPoint(1, fm.descent()), c);
painter->drawText(QPoint(0, fm.descent()), _text->at(i));
painter->setTransform(t);
int width = fm.horizontalAdvance(_text->at(i));
percent += ((qreal)width / (qreal)textWidth) * factor;
}
percent = (1.0 - factor) / 2.0;
}
painter->setPen(_color ? *_color : Qt::black);
for (int i = 0; i < _text->size(); i++) {
QPointF point = _path.pointAtPercent(percent);
qreal angle = _path.angleAtPercent(percent);
painter->translate(point);
painter->rotate(-angle);
painter->drawText(QPoint(0, fm.descent()), _text->at(i));
painter->setTransform(t);
int width = fm.horizontalAdvance(_text->at(i));
percent += ((qreal)width / (qreal)textWidth) * factor;
}
//painter->setBrush(Qt::NoBrush);
//painter->setPen(Qt::red);
//painter->setRenderHint(QPainter::Antialiasing, false);
//painter->drawPath(_shape);
}

View File

@ -1,20 +1,21 @@
#ifndef TEXTPATHITEM_H
#define TEXTPATHITEM_H
#include <QVector>
#include <QPainterPath>
#include "textitem.h"
class QFont;
class QImage;
class QColor;
class TextPathItem : public TextItem
{
public:
TextPathItem() : TextItem(0), _font(0), _color(0) {}
TextPathItem(const QPolygonF &line, const QString *label,
const QRect &tileRect, const QFont *font, const QColor *color,
const QColor *haloColor);
const QColor *haloColor, const QImage *img = 0, bool rotate = true);
TextPathItem(const QPainterPath &line, const QString *label,
const QRect &tileRect, const QFont *font, const QColor *color,
const QColor *haloColor);
const QColor *haloColor, const QImage *img = 0, bool rotate = true);
bool isValid() const {return !_path.isEmpty();}
@ -23,12 +24,14 @@ public:
void paint(QPainter *painter) const;
private:
template<class T> void init(const T &line, const QRect &tileRect);
const QFont *_font;
const QColor *_color;
const QColor *_haloColor;
QPainterPath _path;
const QColor *_color, *_haloColor;
const QImage *_img;
QRectF _rect;
QPainterPath _shape;
QPainterPath _path, _shape;
bool _rotate, _reverse;
};
#endif // TEXTPATHITEM_H

View File

@ -1,3 +1,4 @@
#include <cmath>
#include <QFont>
#include <QFontMetrics>
#include <QImage>
@ -18,9 +19,9 @@ static void expand(QRectF &rect, int width)
TextPointItem::TextPointItem(const QPoint &point, const QString *text,
const QFont *font, const QImage *img, const QColor *color,
const QColor *haloColor, const QColor *bgColor, int padding)
const QColor *haloColor, const QColor *bgColor, int padding, double rotate)
: TextItem(font ? text : 0), _font(font), _img(img), _color(color),
_haloColor(haloColor), _bgColor(bgColor)
_haloColor(haloColor), _bgColor(bgColor), _rotate(rotate)
{
if (_text) {
QFontMetrics fm(*_font);
@ -58,8 +59,17 @@ void TextPointItem::paint(QPainter *painter) const
{
if (_img && !_img->isNull()) {
QSizeF s(_img->size() / _img->devicePixelRatioF());
painter->drawImage(QPointF(_rect.left(), _rect.center().y()
- s.height()/2), *_img);
if (std::isnan(_rotate))
painter->drawImage(QPointF(_rect.left(), _rect.center().y()
- s.height()/2), *_img);
else {
painter->save();
painter->translate(QPointF(_rect.left() + s.width()/2,
_rect.center().y()));
painter->rotate(_rotate);
painter->drawImage(QPointF(-s.width()/2, -s.height()/2), *_img);
painter->restore();
}
}
if (_text) {
@ -99,6 +109,7 @@ void TextPointItem::paint(QPainter *painter) const
}
//painter->setPen(Qt::red);
//painter.setBrush(Qt::NoBrush);
//painter->setRenderHint(QPainter::Antialiasing, false);
//painter->drawRect(_rect);
}

View File

@ -1,12 +1,8 @@
#ifndef TEXTPOINTITEM_H
#define TEXTPOINTITEM_H
#include <QRect>
#include <QString>
#include <QVector>
#include "textitem.h"
class QPainter;
class QFont;
class QImage;
class QColor;
@ -14,10 +10,9 @@ class QColor;
class TextPointItem : public TextItem
{
public:
TextPointItem() : TextItem(0), _font(0), _img(0) {}
TextPointItem(const QPoint &point, const QString *text, const QFont *font,
const QImage *img, const QColor *color, const QColor *haloColor,
const QColor *bgColor = 0, int padding = 0);
const QColor *bgColor = 0, int padding = 0, double rotate = NAN);
bool isValid() const {return !_rect.isEmpty();}
@ -31,6 +26,7 @@ private:
const QFont *_font;
const QImage *_img;
const QColor *_color, *_haloColor, *_bgColor;
double _rotate;
QRectF _rect, _textRect;
QPainterPath _shape;
};

View File

@ -52,7 +52,7 @@ static QString quadKey(const QPoint &xy, int zoom)
}
TileLoader::TileLoader(const QString &dir, QObject *parent)
: QObject(parent), _dir(dir), _scaledSize(0), _quadTiles(false)
: QObject(parent), _urlType(XYZ), _dir(dir), _scaledSize(0)
{
if (!QDir().mkpath(_dir))
qWarning("%s: %s", qPrintable(_dir), "Error creating tiles directory");
@ -176,19 +176,21 @@ QUrl TileLoader::tileUrl(const FetchTile &tile) const
{
QString url(_url);
if (!tile.bbox().isNull()) {
QString bbox = QString("%1,%2,%3,%4").arg(
QString::number(tile.bbox().left(), 'f', 6),
QString::number(tile.bbox().bottom(), 'f', 6),
QString::number(tile.bbox().right(), 'f', 6),
QString::number(tile.bbox().top(), 'f', 6));
url.replace("$bbox", bbox);
} else if (_quadTiles) {
url.replace("$quadkey", quadKey(tile.xy(), tile.zoom().toInt()));
} else {
url.replace("$z", tile.zoom().toString());
url.replace("$x", QString::number(tile.xy().x()));
url.replace("$y", QString::number(tile.xy().y()));
switch (_urlType) {
case BoundingBox:
url.replace("$bbox", QString("%1,%2,%3,%4").arg(
QString::number(tile.bbox().left(), 'f', 6),
QString::number(tile.bbox().bottom(), 'f', 6),
QString::number(tile.bbox().right(), 'f', 6),
QString::number(tile.bbox().top(), 'f', 6)));
break;
case QuadTiles:
url.replace("$quadkey", quadKey(tile.xy(), tile.zoom().toInt()));
break;
default:
url.replace("$z", tile.zoom().toString());
url.replace("$x", QString::number(tile.xy().x()));
url.replace("$y", QString::number(tile.xy().y()));
}
return QUrl(url);

View File

@ -11,12 +11,17 @@ class TileLoader : public QObject
Q_OBJECT
public:
enum UrlType {
XYZ,
QuadTiles,
BoundingBox
};
TileLoader(const QString &dir, QObject *parent = 0);
void setUrl(const QString &url) {_url = url;}
void setUrl(const QString &url, UrlType type) {_url = url; _urlType = type;}
void setHeaders(const QList<HTTPHeader> &headers) {_headers = headers;}
void setScaledSize(int size);
void setQuadTiles(bool quadTiles) {_quadTiles = quadTiles;}
void loadTilesAsync(QVector<FetchTile> &list);
void loadTilesSync(QVector<FetchTile> &list);
@ -31,10 +36,10 @@ private:
Downloader *_downloader;
QString _url;
UrlType _urlType;
QString _dir;
QList<HTTPHeader> _headers;
int _scaledSize;
bool _quadTiles;
};
#endif // TILELOADER_H

View File

@ -85,7 +85,7 @@ WMSMap::WMSMap(const QString &fileName, const QString &name,
void WMSMap::init()
{
_tileLoader->setUrl(tileUrl());
_tileLoader->setUrl(tileUrl(), TileLoader::BoundingBox);
_bounds = RectD(_wms->bbox(), _wms->projection());
computeZooms();
updateTransform();

View File

@ -31,7 +31,7 @@ WMTSMap::WMTSMap(const QString &fileName, const QString &name,
void WMTSMap::init()
{
_tileLoader->setUrl(_wmts->tileUrl());
_tileLoader->setUrl(_wmts->tileUrl(), TileLoader::XYZ);
_bounds = RectD(_wmts->bbox(), _wmts->projection());
updateTransform();
}