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

Compare commits

...

96 Commits
7.10 ... 7.15

Author SHA1 Message Date
a24d55025f Text layout tweaking & optimization 2019-10-05 12:41:42 +02:00
04ddcecb70 Increased tile cache size 2019-10-03 22:47:31 +02:00
dc9a600a6e Version++ 2019-10-03 01:06:53 +02:00
c365de130b Properly align the zoom 0 level with tiles of a different size than 256 2019-10-02 23:58:58 +02:00
d3558198ca Translated using Weblate (German)
Currently translated at 100.0% (343 of 343 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/de/
2019-09-29 11:58:18 +02:00
acc69f5c3d Merge branch 'origin/master' into Weblate. 2019-09-29 11:47:55 +02:00
7a900f2252 Version++ 2019-09-29 11:48:08 +02:00
dad76a4e89 Merge branch 'origin/master' into Weblate. 2019-09-29 11:24:33 +02:00
e28e69b248 Added support for enchanced altitude and speed entries 2019-09-29 11:24:20 +02:00
7fffd6a161 Merge branch 'origin/master' into Weblate. 2019-09-29 00:03:21 +02:00
c4fd82e5a0 Properly handle routes without elevation data as well 2019-09-29 00:03:14 +02:00
fa08c0dbea Properly handle files without elevation data 2019-09-28 23:56:59 +02:00
070eff2115 Print a warning message on unsupported IMG compression 2019-09-28 23:55:26 +02:00
20a4870904 Merge branch 'origin/master' into Weblate. 2019-09-21 00:37:02 +02:00
1bb9908936 Some more code cleanup 2019-09-21 00:36:49 +02:00
36555b3140 Code cleanup 2019-09-20 00:23:47 +02:00
6564fb36ab Merge branch 'origin/master' into Weblate. 2019-09-20 00:23:46 +02:00
1a3356b8fe Cosmetics 2019-09-18 09:18:09 +02:00
7ad64922c9 Merge branch 'origin/master' into Weblate. 2019-09-18 09:18:09 +02:00
64a8ec1b84 Merge branch 'origin/master' into Weblate. 2019-09-18 09:12:36 +02:00
0a75298b2b Made the variable record info parsing universal 2019-09-18 09:11:46 +02:00
99be5699af Merge branch 'origin/master' into Weblate. 2019-09-18 08:38:05 +02:00
cdb641b204 Properly read variable length values
Code cleanup
2019-09-18 08:37:33 +02:00
f57bd48840 Merge branch 'origin/master' into Weblate. 2019-09-10 19:45:52 +02:00
c2abf2c146 Prefer loading speed over "NT maps not supported" reporting 2019-09-10 19:45:06 +02:00
a5a2070ccc Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (343 of 343 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/pt_BR/
2019-09-09 12:35:04 +02:00
ed7cb1beb1 Translated using Weblate (Norwegian Bokmål)
Currently translated at 91.3% (313 of 343 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/nb_NO/
2019-09-09 12:35:04 +02:00
37d832bc7f Translated using Weblate (French)
Currently translated at 100.0% (343 of 343 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/fr/
2019-09-09 12:35:04 +02:00
c322bf9f68 Translated using Weblate (Turkish)
Currently translated at 100.0% (343 of 343 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/tr/
2019-09-07 21:35:43 +02:00
2705ffbbfe Translated using Weblate (Russian)
Currently translated at 100.0% (343 of 343 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/ru/
2019-09-07 00:22:41 +02:00
e8962dd50f Translated using Weblate (Czech)
Currently translated at 100.0% (343 of 343 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/cs/
2019-09-07 00:22:40 +02:00
b37e32d622 Translated using Weblate (Finnish)
Currently translated at 100.0% (343 of 343 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/fi/
2019-09-07 00:22:40 +02:00
2b1d0d2189 Translated using Weblate (Swedish)
Currently translated at 100.0% (343 of 343 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/sv/
2019-09-07 00:22:39 +02:00
33e3471ca3 Added pt_PT translation file stub 2019-09-06 20:10:40 +02:00
bf55f1e07d ts files update 2019-09-06 20:10:09 +02:00
37a0eec48f Added support for pseudo-NT IMG maps (e.g. TopoHispania) 2019-09-05 22:31:13 +02:00
fcaacb4b6a Version++ 2019-08-29 20:18:35 +02:00
f9c593e6d1 Fixed the "DEM values not used in route points" issue 2019-08-29 20:15:03 +02:00
37e07accd4 Fixed percent slider updates 2019-08-27 20:19:06 +02:00
a7117361be Cosmetics 2019-08-27 20:18:39 +02:00
548c03d543 Added support for graph zooming 2019-08-26 21:03:40 +02:00
1addb1118d Fixed broken maximal ticks count limitation 2019-08-26 20:40:14 +02:00
ae64ef9d83 Only use B records with a valid fix in IGC files 2019-08-25 13:05:27 +02:00
3d16cf2500 Removed forgotten debug stuff 2019-08-25 11:38:41 +02:00
609ac0c57a Graph loading performance improvement
+ code/API cleanup
2019-08-25 10:54:25 +02:00
a70c6f0f24 Fixed broken gear ratio statistics 2019-08-22 19:56:55 +02:00
3ad0c89511 Added missing area-under-mouse highlighting 2019-08-19 19:22:16 +02:00
1497d42bd5 Added CUP files support info 2019-08-18 00:13:04 +02:00
a4906e7d01 Translated using Weblate (Spanish)
Currently translated at 98.5% (337 of 342 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/es/
2019-08-17 20:15:59 +02:00
f56dfd95e3 Merge branch 'origin/master' into Weblate. 2019-08-17 11:07:57 +02:00
2bda7ba714 Ignore "???" turnpoints in CUP tasks 2019-08-17 11:07:28 +02:00
940bd0511e Merge branch 'origin/master' into Weblate. 2019-08-17 10:45:16 +02:00
30518cebc0 Fixed CUP task parsing 2019-08-17 10:44:53 +02:00
696bc50ba1 Merge branch 'origin/master' into Weblate. 2019-08-16 21:33:03 +02:00
b91358a6bd Added CUP files OS X desktop integration 2019-08-16 21:32:31 +02:00
94eab9fba0 Merge branch 'origin/master' into Weblate. 2019-08-16 20:51:20 +02:00
44b98754d7 Version++ 2019-08-16 20:50:59 +02:00
8451178808 Merge branch 'origin/master' into Weblate. 2019-08-16 20:47:25 +02:00
7eedcc083e CUP files Windows & Linux desktop integration 2019-08-16 20:46:42 +02:00
cd32b21aca Merge branch 'origin/master' into Weblate. 2019-08-16 18:33:27 +02:00
e1bda86b35 Use the whole waypoint info in the route points
+ Optimize for waypoint reading
2019-08-16 18:32:55 +02:00
967e307be9 Fixed QT4 build 2019-08-15 22:10:25 +02:00
7cf1e3e1a5 Merge branch 'origin/master' into Weblate. 2019-08-15 22:10:11 +02:00
0f44feebb1 Merge branch 'origin/master' into Weblate. 2019-08-15 21:28:40 +02:00
ecb82952f6 Added support for SeeYou CUP files 2019-08-15 21:27:55 +02:00
ab6ea84255 Some more cleanup 2019-08-13 20:50:43 +02:00
0b2d610a34 Merge branch 'origin/master' into Weblate. 2019-08-13 20:50:30 +02:00
f67eaa8dec Various code cleanup 2019-08-12 22:20:12 +02:00
2a619aa0ef Merge branch 'origin/master' into Weblate. 2019-08-12 22:20:03 +02:00
dd292bc995 Merge branch 'origin/master' into Weblate. 2019-08-11 09:28:08 +02:00
680104fec3 Fixed lat/lon reference parsing in big endian EXIF entries
Closes #218
2019-08-11 09:26:54 +02:00
b72a9e67fe Cosmetics 2019-08-01 18:58:19 +02:00
24b7b9d996 Merge branch 'origin/master' into Weblate. 2019-08-01 18:58:18 +02:00
7965f2ff34 Merge branch 'origin/master' into Weblate. 2019-08-01 08:38:29 +02:00
5f5b391cd9 Added support for Geographic 2D projections (coordinate systems) in vector maps 2019-08-01 08:36:58 +02:00
faed6fc203 Merge branch 'origin/master' into Weblate. 2019-07-28 11:59:40 +02:00
38b62c0121 Added missing libqt4-opengl-dev package install 2019-07-28 11:58:56 +02:00
f26f8a95ac Merge branch 'origin/master' into Weblate. 2019-07-28 10:34:32 +02:00
1297db26f6 Properly de-capitalize strings with "scharfes S" 2019-07-28 10:31:03 +02:00
2ee955172d Translated using Weblate (French)
Currently translated at 100.0% (342 of 342 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/fr/
2019-07-26 14:31:49 +02:00
a11b926a98 Version++ 2019-07-18 08:14:47 +02:00
70b5371a6e Improved error handling 2019-07-18 00:26:27 +02:00
d07b6c6a9d Load TRE subdivs on demand, not all on tile load 2019-07-16 22:08:23 +02:00
c9a62e8b61 Removed obsolete stuff 2019-07-16 00:23:08 +02:00
aa3579c0be Fixed QT4 build 2019-07-13 15:14:29 +02:00
297177ad41 Cosmetics 2019-07-13 14:42:44 +02:00
0e9720f68b Optimization 2019-07-13 14:18:16 +02:00
c1f36e5fbb Improved shields layout algorithm 2019-07-13 08:36:04 +02:00
a20fd3e474 Fixed cut&paste error 2019-07-11 18:55:12 +02:00
aba78f3baa Properly handle self-asignments 2019-07-10 23:08:58 +02:00
2f24bb5462 Some more code cleanup 2019-07-10 21:49:46 +02:00
c1fdb21fad Cosmetics 2019-07-10 21:37:03 +02:00
6bea3b7ebf Suppress QT's deprecated functions warnings 2019-07-10 21:17:52 +02:00
a7efa80e8f Merge branch 'master' of https://github.com/tumic0/GPXSee 2019-07-08 21:19:54 +02:00
4e9faf3a23 Code cleanup 2019-07-08 21:19:25 +02:00
d4e153d10f Updated PL translation (#217) 2019-07-08 08:31:43 +02:00
123 changed files with 7799 additions and 3746 deletions

View File

@ -1,4 +1,4 @@
version: 7.10.{build}
version: 7.15.{build}
configuration: Release
platform: Any CPU
environment:

View File

@ -9,7 +9,7 @@ before_install:
install:
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install qt; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install libqt4-dev; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install libqt4-dev libqt4-opengl-dev; fi
script:
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then PATH=/usr/local/opt/qt/bin/:${PATH}; fi

View File

@ -2,7 +2,7 @@
GPXSee is a Qt-based GPS log file viewer and analyzer that supports all common GPS log file formats.
## Features
* Opens GPX, TCX, FIT, KML, IGC, NMEA, SLF, LOC, GeoJSON, OziExplorer (PLT, RTE, WPT), Garmin CSV and geotagged JPEG files.
* Opens GPX, TCX, FIT, KML, NMEA, IGC, CUP, SLF, LOC, GeoJSON, OziExplorer (PLT, RTE, WPT), Garmin CSV and geotagged JPEG files.
* User-definable online maps (OpenStreetMap/Google tiles, WMTS, WMS, TMS, QuadTiles).
* Offline maps (MBTiles, OziExplorer maps, TrekBuddy maps/atlases, Garmin IMG & JNX maps, TwoNav RMaps, GeoTIFF images).
* Elevation, speed, heart rate, cadence, power, temperature and gear ratio/shifts graphs.

View File

@ -3,7 +3,7 @@ unix:!macx {
} else {
TARGET = GPXSee
}
VERSION = 7.10
VERSION = 7.15
QT += core \
gui \
@ -181,7 +181,9 @@ HEADERS += src/common/config.h \
src/GUI/limitedcombobox.h \
src/GUI/pathtickitem.h \
src/map/IMG/textitem.h \
src/map/IMG/label.h
src/map/IMG/label.h \
src/data/csv.h \
src/data/cupparser.h
SOURCES += src/main.cpp \
src/common/coordinates.cpp \
src/common/rectc.cpp \
@ -312,14 +314,17 @@ SOURCES += src/main.cpp \
src/map/IMG/style.cpp \
src/map/IMG/netfile.cpp \
src/GUI/pathtickitem.cpp \
src/map/IMG/textitem.cpp
src/map/IMG/textitem.cpp \
src/data/csv.cpp \
src/data/cupparser.cpp
greaterThan(QT_MAJOR_VERSION, 4) {
HEADERS += src/data/geojsonparser.h
SOURCES += src/data/geojsonparser.cpp
}
DEFINES += APP_VERSION=\\\"$$VERSION\\\"
DEFINES += APP_VERSION=\\\"$$VERSION\\\" \
QT_NO_DEPRECATED_WARNINGS
DEFINES *= QT_USE_QSTRINGBUILDER
RESOURCES += gpxsee.qrc
@ -370,7 +375,8 @@ macx {
icons/formats/wpt.icns \
icons/formats/loc.icns \
icons/formats/slf.icns \
icons/formats/json.icns
icons/formats/json.icns \
icons/formats/cup.icns
QMAKE_BUNDLE_DATA += locale maps icons csv
}
@ -387,7 +393,8 @@ win32 {
icons/formats/wpt.ico \
icons/formats/loc.ico \
icons/formats/slf.ico \
icons/formats/json.ico
icons/formats/json.ico \
icons/formats/cup.ico
DEFINES += _USE_MATH_DEFINES \
NOGDI
}

BIN
icons/formats/cup.icns Normal file

Binary file not shown.

BIN
icons/formats/cup.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 KiB

View File

@ -10,3 +10,4 @@ tcx:#ffcc00
wpt:#66ff00
loc:#556677
slf:#881199
cup:#20a810

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

1860
lang/gpxsee_pt_PT.ts Normal file

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

@ -211,6 +211,22 @@
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>cup</string>
</array>
<key>CFBundleTypeMIMETypes</key>
<array>
<string>application/vnd.naviter.seeyou.cup</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>icons/cup.icns</string>
<key>CFBundleTypeName</key>
<string>SeeYou CUP File</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
</array>
<key>UTImportedTypeDeclarations</key>
@ -467,6 +483,27 @@
<string>application/geo+json</string>
</dict>
</dict>
<dict>
<key>UTTypeIdentifier</key>
<string>com.naviter.seeyou.cup</string>
<key>UTTypeReferenceURL</key>
<string>http://www.naviter.com</string>
<key>UTTypeDescription</key>
<string>SeeYou CUP File</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>cup</string>
</array>
<key>public.mime-type</key>
<string>application/vnd.naviter.seeyou.cup</string>
</dict>
</dict>
</array>
</dict>
</plist>

View File

@ -13,7 +13,8 @@
<p>Features:</p>
<ul>
<li>Opens GPX, TCX, FIT, KML, IGC, NMEA, SLF, LOC, OziExplorer (PLT,
WPT, RTE), GeoJSON, Garmin CSV and geotagged JPEG files.</li>
WPT, RTE), GeoJSON, SeeYou CUP, Garmin CSV and geotagged
JPEG files.</li>
<li>User-definable online maps (OpenStreetMap/Google tiles, WMTS,
WMS, TMS).</li>
<li>Offline maps (MBTiles, OziExplorer maps, TrekBuddy maps/atlases,
@ -67,5 +68,6 @@
<mimetype>application/loc+xml</mimetype>
<mimetype>application/slf+xml</mimetype>
<mimetype>application/geo+json</mimetype>
<mimetype>application/vnd.naviter.seeyou.cup</mimetype>
</mimetypes>
</component>

View File

@ -11,4 +11,4 @@ Icon=gpxsee
Terminal=false
Type=Application
Categories=Graphics;Viewer;Education;Geography;Maps;Sports;Qt;
MimeType=application/gpx+xml;application/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/loc+xml;application/slf+xml;application/geo+json;
MimeType=application/gpx+xml;application/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/loc+xml;application/slf+xml;application/geo+json;application/vnd.naviter.seeyou.cup;

View File

@ -7,7 +7,7 @@
; The name of the installer
Name "GPXSee"
; Program version
!define VERSION "7.10"
!define VERSION "7.15"
; The file to write
OutFile "GPXSee-${VERSION}.exe"
@ -106,18 +106,19 @@ Section "GPXSee" SEC_APP
; Associate file formats
DetailPrint "Associating file types..."
!insertmacro FILE_ASSOCIATION_ADD "gpx" "GPS Exchange Format" 5
!insertmacro FILE_ASSOCIATION_ADD "tcx" "Training Center XML" 6
!insertmacro FILE_ASSOCIATION_ADD "kml" "Keyhole Markup Language" 7
!insertmacro FILE_ASSOCIATION_ADD "fit" "Flexible and Interoperable Data Transfer" 8
!insertmacro FILE_ASSOCIATION_ADD "igc" "Flight Recorder Data Format" 9
!insertmacro FILE_ASSOCIATION_ADD "nmea" "NMEA 0183 data" 10
!insertmacro FILE_ASSOCIATION_ADD "plt" "OziExplorer Track Point File" 11
!insertmacro FILE_ASSOCIATION_ADD "rte" "OziExplorer Route File" 12
!insertmacro FILE_ASSOCIATION_ADD "gpx" "GPS Exchange Format" 6
!insertmacro FILE_ASSOCIATION_ADD "tcx" "Training Center XML" 7
!insertmacro FILE_ASSOCIATION_ADD "kml" "Keyhole Markup Language" 8
!insertmacro FILE_ASSOCIATION_ADD "fit" "Flexible and Interoperable Data Transfer" 9
!insertmacro FILE_ASSOCIATION_ADD "igc" "Flight Recorder Data Format" 10
!insertmacro FILE_ASSOCIATION_ADD "nmea" "NMEA 0183 data" 11
!insertmacro FILE_ASSOCIATION_ADD "plt" "OziExplorer Track Point File" 12
!insertmacro FILE_ASSOCIATION_ADD "rte" "OziExplorer Route File" 13
!insertmacro FILE_ASSOCIATION_ADD "wpt" "OziExplorer Waypoint File" 1
!insertmacro FILE_ASSOCIATION_ADD "loc" "Geocaching.com Waypoint File" 2
!insertmacro FILE_ASSOCIATION_ADD "slf" "Sigma Log File" 3
!insertmacro FILE_ASSOCIATION_ADD "geojson" "GeoJSON" 4
!insertmacro FILE_ASSOCIATION_ADD "cup" "SeeYou CUP file" 5
System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)'
SectionEnd
@ -227,6 +228,7 @@ Section "Uninstall"
!insertmacro FILE_ASSOCIATION_REMOVE "loc"
!insertmacro FILE_ASSOCIATION_REMOVE "slf"
!insertmacro FILE_ASSOCIATION_REMOVE "geojson"
!insertmacro FILE_ASSOCIATION_REMOVE "cup"
System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)'
SectionEnd
@ -257,4 +259,4 @@ LangString DESC_LOCALIZATION ${LANG_ENGLISH} \
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_MSVC} $(DESC_MSVC)
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_APP} $(DESC_APP)
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_LOCALIZATION} $(DESC_LOCALIZATION)
!insertmacro MUI_FUNCTION_DESCRIPTION_END
!insertmacro MUI_FUNCTION_DESCRIPTION_END

View File

@ -84,4 +84,11 @@
<generic-icon name="text-plain"/>
<glob pattern="*.geojson"/>
</mime-type>
<mime-type type="application/vnd.naviter.seeyou.cup">
<comment>SeeYou CUP File</comment>
<sub-class-of type="text/plain"/>
<generic-icon name="text-plain"/>
<glob pattern="*.cup"/>
</mime-type>
</mime-info>

View File

@ -7,7 +7,7 @@
; The name of the installer
Name "GPXSee"
; Program version
!define VERSION "7.10"
!define VERSION "7.15"
; The file to write
OutFile "GPXSee-${VERSION}_x64.exe"
@ -113,18 +113,19 @@ Section "GPXSee" SEC_APP
; Associate file formats
DetailPrint "Associating file types..."
!insertmacro FILE_ASSOCIATION_ADD "gpx" "GPS Exchange Format" 5
!insertmacro FILE_ASSOCIATION_ADD "tcx" "Training Center XML" 6
!insertmacro FILE_ASSOCIATION_ADD "kml" "Keyhole Markup Language" 7
!insertmacro FILE_ASSOCIATION_ADD "fit" "Flexible and Interoperable Data Transfer" 8
!insertmacro FILE_ASSOCIATION_ADD "igc" "Flight Recorder Data Format" 9
!insertmacro FILE_ASSOCIATION_ADD "nmea" "NMEA 0183 data" 10
!insertmacro FILE_ASSOCIATION_ADD "plt" "OziExplorer Track Point File" 11
!insertmacro FILE_ASSOCIATION_ADD "rte" "OziExplorer Route File" 12
!insertmacro FILE_ASSOCIATION_ADD "gpx" "GPS Exchange Format" 6
!insertmacro FILE_ASSOCIATION_ADD "tcx" "Training Center XML" 7
!insertmacro FILE_ASSOCIATION_ADD "kml" "Keyhole Markup Language" 8
!insertmacro FILE_ASSOCIATION_ADD "fit" "Flexible and Interoperable Data Transfer" 9
!insertmacro FILE_ASSOCIATION_ADD "igc" "Flight Recorder Data Format" 10
!insertmacro FILE_ASSOCIATION_ADD "nmea" "NMEA 0183 data" 11
!insertmacro FILE_ASSOCIATION_ADD "plt" "OziExplorer Track Point File" 12
!insertmacro FILE_ASSOCIATION_ADD "rte" "OziExplorer Route File" 13
!insertmacro FILE_ASSOCIATION_ADD "wpt" "OziExplorer Waypoint File" 1
!insertmacro FILE_ASSOCIATION_ADD "loc" "Geocaching.com Waypoint File" 2
!insertmacro FILE_ASSOCIATION_ADD "slf" "Sigma Log File" 3
!insertmacro FILE_ASSOCIATION_ADD "geojson" "GeoJSON" 4
!insertmacro FILE_ASSOCIATION_ADD "cup" "SeeYou CUP file" 5
System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)'
SectionEnd
@ -230,6 +231,7 @@ Section "Uninstall"
!insertmacro FILE_ASSOCIATION_REMOVE "loc"
!insertmacro FILE_ASSOCIATION_REMOVE "slf"
!insertmacro FILE_ASSOCIATION_REMOVE "geojson"
!insertmacro FILE_ASSOCIATION_REMOVE "cup"
System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)'
SectionEnd
@ -260,4 +262,4 @@ LangString DESC_LOCALIZATION ${LANG_ENGLISH} \
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_MSVC} $(DESC_MSVC)
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_APP} $(DESC_APP)
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_LOCALIZATION} $(DESC_LOCALIZATION)
!insertmacro MUI_FUNCTION_DESCRIPTION_END
!insertmacro MUI_FUNCTION_DESCRIPTION_END

View File

@ -153,3 +153,21 @@ void AreaItem::setDigitalZoom(int zoom)
_digitalZoom = zoom;
_pen.setWidthF(_width * pow(2, -_digitalZoom));
}
void AreaItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event);
_pen.setWidthF((_width + 1) * pow(2, -_digitalZoom));
setZValue(zValue() + 1.0);
update();
}
void AreaItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event);
_pen.setWidthF(_width * pow(2, -_digitalZoom));
setZValue(zValue() - 1.0);
update();
}

View File

@ -27,6 +27,9 @@ public:
void setDigitalZoom(int zoom);
private:
void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
QPainterPath painterPath(const Polygon &polygon);
void updatePainterPath();
QString toolTip() const;

View File

@ -30,7 +30,7 @@ private:
Ticks::Ticks(double minValue, double maxValue, int maxCount)
{
double range = niceNum(maxValue - minValue, false);
_d = niceNum(range / maxCount, true);
_d = niceNum(range / maxCount, false);
_min = ceil(minValue / _d) * _d;
_max = floor(maxValue / _d) * _d;
}

View File

@ -14,6 +14,11 @@ CadenceGraph::CadenceGraph(QWidget *parent) : GraphTab(parent)
setSliderPrecision(1);
}
CadenceGraph::~CadenceGraph()
{
qDeleteAll(_tracks);
}
void CadenceGraph::setInfo()
{
if (_showTracks) {
@ -36,23 +41,28 @@ QList<GraphItem*> CadenceGraph::loadData(const Data &data)
const Graph &graph = track.cadence();
if (!graph.isValid()) {
skipColor();
_palette.nextColor();
graphs.append(0);
} else {
CadenceGraphItem *gi = new CadenceGraphItem(graph, _graphType);
GraphView::addGraph(gi);
CadenceGraphItem *gi = new CadenceGraphItem(graph, _graphType,
_width, _palette.nextColor());
_tracks.append(gi);
if (_showTracks)
addGraph(gi);
_avg.append(QPointF(track.distance(), gi->avg()));
graphs.append(gi);
}
}
for (int i = 0; i < data.routes().count(); i++) {
skipColor();
_palette.nextColor();
graphs.append(0);
}
for (int i = 0; i < data.areas().count(); i++)
skipColor();
_palette.nextColor();
setInfo();
redraw();
@ -75,6 +85,9 @@ qreal CadenceGraph::avg() const
void CadenceGraph::clear()
{
qDeleteAll(_tracks);
_tracks.clear();
_avg.clear();
GraphTab::clear();
@ -84,7 +97,13 @@ void CadenceGraph::showTracks(bool show)
{
_showTracks = show;
showGraph(show);
for (int i = 0; i < _tracks.size(); i++) {
if (show)
addGraph(_tracks.at(i));
else
removeGraph(_tracks.at(i));
}
setInfo();
redraw();

View File

@ -3,18 +3,20 @@
#include "graphtab.h"
class CadenceGraphItem;
class CadenceGraph : public GraphTab
{
Q_OBJECT
public:
CadenceGraph(QWidget *parent = 0);
~CadenceGraph();
QString label() const {return tr("Cadence");}
QList<GraphItem*> loadData(const Data &data);
void clear();
void showTracks(bool show);
void showRoutes(bool show) {Q_UNUSED(show);}
private:
qreal avg() const;
@ -24,6 +26,7 @@ private:
QVector<QPointF> _avg;
bool _showTracks;
QList<CadenceGraphItem *> _tracks;
};
#endif // CADENCEGRAPH_H

View File

@ -4,7 +4,8 @@
CadenceGraphItem::CadenceGraphItem(const Graph &graph, GraphType type,
QGraphicsItem *parent) : GraphItem(graph, type, parent)
int width, const QColor &color, QGraphicsItem *parent)
: GraphItem(graph, type, width, color, parent)
{
setToolTip(toolTip());
}

View File

@ -8,8 +8,8 @@ class CadenceGraphItem : public GraphItem
Q_OBJECT
public:
CadenceGraphItem(const Graph &graph, GraphType type,
QGraphicsItem *parent = 0);
CadenceGraphItem(const Graph &graph, GraphType type, int width,
const QColor &color, QGraphicsItem *parent = 0);
private:
QString toolTip() const;

View File

@ -8,26 +8,18 @@
static qreal nMin(qreal a, qreal b)
{
if (!std::isnan(a) && !std::isnan(b))
return qMin(a, b);
else if (!std::isnan(a))
return a;
else if (!std::isnan(b))
return b;
if (std::isnan(a))
return std::isnan(b) ? NAN : b;
else
return NAN;
return std::isnan(b) ? a : qMin(a, b);
}
static qreal nMax(qreal a, qreal b)
{
if (!std::isnan(a) && !std::isnan(b))
return qMax(a, b);
else if (!std::isnan(a))
return a;
else if (!std::isnan(b))
return b;
if (std::isnan(a))
return std::isnan(b) ? NAN : b;
else
return NAN;
return std::isnan(b) ? a : qMax(a, b);
}
ElevationGraph::ElevationGraph(QWidget *parent) : GraphTab(parent)
@ -49,6 +41,12 @@ ElevationGraph::ElevationGraph(QWidget *parent) : GraphTab(parent)
setMinYRange(50.0);
}
ElevationGraph::~ElevationGraph()
{
qDeleteAll(_tracks);
qDeleteAll(_routes);
}
void ElevationGraph::setInfo()
{
if (std::isnan(max()) || std::isnan(min()))
@ -70,19 +68,28 @@ void ElevationGraph::setInfo()
GraphItem *ElevationGraph::loadGraph(const Graph &graph, Type type)
{
if (!graph.isValid()) {
skipColor();
_palette.nextColor();
return 0;
}
ElevationGraphItem *gi = new ElevationGraphItem(graph, _graphType);
GraphView::addGraph(gi, type);
ElevationGraphItem *gi = new ElevationGraphItem(graph, _graphType, _width,
_palette.nextColor());
gi->setUnits(_units);
if (type == Track) {
_tracks.append(gi);
if (_showTracks)
addGraph(gi);
_trackAscent += gi->ascent();
_trackDescent += gi->descent();
_trackMax = nMax(_trackMax, gi->max());
_trackMin = nMin(_trackMin, gi->min());
} else {
_routes.append(gi);
if (_showRoutes)
addGraph(gi);
_routeAscent += gi->ascent();
_routeDescent += gi->descent();
_routeMax = nMax(_routeMax, gi->max());
@ -101,7 +108,7 @@ QList<GraphItem*> ElevationGraph::loadData(const Data &data)
for (int i = 0; i < data.routes().count(); i++)
graphs.append(loadGraph(data.routes().at(i).elevation(), Route));
for (int i = 0; i < data.areas().count(); i++)
skipColor();
_palette.nextColor();
setInfo();
redraw();
@ -111,6 +118,11 @@ QList<GraphItem*> ElevationGraph::loadData(const Data &data)
void ElevationGraph::clear()
{
qDeleteAll(_tracks);
_tracks.clear();
qDeleteAll(_routes);
_routes.clear();
_trackAscent = 0;
_routeAscent = 0;
_trackDescent = 0;
@ -142,12 +154,23 @@ void ElevationGraph::setUnits(Units units)
GraphView::setUnits(units);
}
void ElevationGraph::showItems(const QList<ElevationGraphItem *> &list,
bool show)
{
for (int i = 0; i < list.size(); i++) {
if (show)
addGraph(list.at(i));
else
removeGraph(list.at(i));
}
}
void ElevationGraph::showTracks(bool show)
{
_showTracks = show;
showItems(_tracks, show);
setInfo();
showGraph(show, Track);
redraw();
}
@ -156,7 +179,7 @@ void ElevationGraph::showRoutes(bool show)
{
_showRoutes = show;
showGraph(show, Route);
showItems(_routes, show);
setInfo();
redraw();

View File

@ -3,12 +3,15 @@
#include "graphtab.h"
class ElevationGraphItem;
class ElevationGraph : public GraphTab
{
Q_OBJECT
public:
ElevationGraph(QWidget *parent = 0);
~ElevationGraph();
QString label() const {return tr("Elevation");}
QList<GraphItem*> loadData(const Data &data);
@ -29,6 +32,7 @@ private:
void setInfo();
GraphItem *loadGraph(const Graph &graph, Type type);
void showItems(const QList<ElevationGraphItem *> &list, bool show);
qreal _trackAscent, _trackDescent;
qreal _routeAscent, _routeDescent;
@ -36,6 +40,7 @@ private:
qreal _trackMin, _routeMin;
bool _showTracks, _showRoutes;
QList<ElevationGraphItem *> _tracks, _routes;
};
#endif // ELEVATIONGRAPH_H

View File

@ -4,7 +4,8 @@
ElevationGraphItem::ElevationGraphItem(const Graph &graph, GraphType type,
QGraphicsItem *parent) : GraphItem(graph, type, parent)
int width, const QColor &color, QGraphicsItem *parent)
: GraphItem(graph, type, width, color, parent)
{
_min = GraphItem::min();
_max = GraphItem::max();

View File

@ -8,8 +8,8 @@ class ElevationGraphItem : public GraphItem
Q_OBJECT
public:
ElevationGraphItem(const Graph &graph, GraphType type,
QGraphicsItem *parent = 0);
ElevationGraphItem(const Graph &graph, GraphType type, int width,
const QColor &color, QGraphicsItem *parent = 0);
qreal ascent() const {return _ascent;}
qreal descent() const {return _descent;}

View File

@ -14,6 +14,11 @@ GearRatioGraph::GearRatioGraph(QWidget *parent) : GraphTab(parent)
setSliderPrecision(2);
}
GearRatioGraph::~GearRatioGraph()
{
qDeleteAll(_tracks);
}
void GearRatioGraph::setInfo()
{
if (_showTracks) {
@ -37,11 +42,15 @@ QList<GraphItem*> GearRatioGraph::loadData(const Data &data)
const Graph &graph = data.tracks().at(i).ratio();
if (!graph.isValid()) {
skipColor();
_palette.nextColor();
graphs.append(0);
} else {
GearRatioGraphItem *gi = new GearRatioGraphItem(graph, _graphType);
GraphView::addGraph(gi);
GearRatioGraphItem *gi = new GearRatioGraphItem(graph, _graphType,
_width, _palette.nextColor());
_tracks.append(gi);
if (_showTracks)
addGraph(gi);
for (QMap<qreal, qreal>::const_iterator it = gi->map().constBegin();
it != gi->map().constEnd(); ++it)
@ -51,12 +60,12 @@ QList<GraphItem*> GearRatioGraph::loadData(const Data &data)
}
for (int i = 0; i < data.routes().count(); i++) {
skipColor();
_palette.nextColor();
graphs.append(0);
}
for (int i = 0; i < data.areas().count(); i++)
skipColor();
_palette.nextColor();
setInfo();
redraw();
@ -70,10 +79,7 @@ qreal GearRatioGraph::top() const
for (QMap<qreal, qreal>::const_iterator it = _map.constBegin();
it != _map.constEnd(); ++it) {
if (it == _map.constBegin()) {
val = it.value();
key = it.key();
} else if (it.value() > val) {
if (std::isnan(val) || it.value() > val) {
val = it.value();
key = it.key();
}
@ -84,6 +90,9 @@ qreal GearRatioGraph::top() const
void GearRatioGraph::clear()
{
qDeleteAll(_tracks);
_tracks.clear();
_map.clear();
GraphTab::clear();
@ -93,7 +102,13 @@ void GearRatioGraph::showTracks(bool show)
{
_showTracks = show;
showGraph(show);
for (int i = 0; i < _tracks.size(); i++) {
if (show)
addGraph(_tracks.at(i));
else
removeGraph(_tracks.at(i));
}
setInfo();
redraw();

View File

@ -4,12 +4,15 @@
#include <QMap>
#include "graphtab.h"
class GearRatioGraphItem;
class GearRatioGraph : public GraphTab
{
Q_OBJECT
public:
GearRatioGraph(QWidget *parent = 0);
~GearRatioGraph();
QString label() const {return tr("Gear ratio");}
QList<GraphItem*> loadData(const Data &data);
@ -25,6 +28,7 @@ private:
QMap<qreal, qreal> _map;
bool _showTracks;
QList<GearRatioGraphItem*> _tracks;
};
#endif // GEARRATIOGRAPH_H

View File

@ -5,21 +5,27 @@
GearRatioGraphItem::GearRatioGraphItem(const Graph &graph, GraphType type,
QGraphicsItem *parent) : GraphItem(graph, type, parent), _top(NAN)
int width, const QColor &color, QGraphicsItem *parent)
: GraphItem(graph, type, width, color, parent)
{
qreal val = NAN;
for (QMap<qreal, qreal>::const_iterator it = _map.constBegin();
it != _map.constEnd(); ++it) {
if (it == _map.constBegin()) {
val = it.value();
_top = it.key();
} else if (it.value() > val) {
val = it.value();
_top = it.key();
for (int i = 0; i < graph.size(); i++) {
const GraphSegment &segment = graph.at(i);
for (int j = 1; j < segment.size(); j++) {
qreal dx = segment.at(j).s() - segment.at(j-1).s();
_map.insert(segment.at(j).y(), _map.value(segment.at(j).y()) + dx);
}
}
qreal key = NAN, val = NAN;
for (QMap<qreal, qreal>::const_iterator it = _map.constBegin();
it != _map.constEnd(); ++it) {
if (std::isnan(val) || it.value() > val) {
val = it.value();
key = it.key();
}
}
_top = key;
setToolTip(toolTip());
}

View File

@ -9,8 +9,8 @@ class GearRatioGraphItem : public GraphItem
Q_OBJECT
public:
GearRatioGraphItem(const Graph &graph, GraphType type,
QGraphicsItem *parent = 0);
GearRatioGraphItem(const Graph &graph, GraphType type, int width,
const QColor &color, QGraphicsItem *parent = 0);
qreal top() const {return _top;}

View File

@ -2,30 +2,25 @@
#include "graphitem.h"
GraphItem::GraphItem(const Graph &graph, GraphType type, QGraphicsItem *parent)
GraphItem::GraphItem(const Graph &graph, GraphType type, int width,
const QColor &color, QGraphicsItem *parent)
: QGraphicsObject(parent), _graph(graph), _type(type)
{
Q_ASSERT(_graph.isValid());
_id = 0;
_width = 1;
_pen = QPen(Qt::black, _width);
_sx = 1.0; _sy = 1.0;
_pen = QPen(color, width);
_sx = 0; _sy = 0;
_time = _graph.hasTime();
setZValue(2.0);
updatePath();
updateShape();
updateBounds();
setAcceptHoverEvents(true);
updateBounds();
}
void GraphItem::updateShape()
{
QPainterPathStroker s;
s.setWidth(_width + 1);
s.setWidth(_pen.width() + 1);
_shape = s.createStroke(_path);
}
@ -54,7 +49,6 @@ void GraphItem::setGraphType(GraphType type)
_type = type;
updatePath();
updateShape();
updateBounds();
}
@ -69,12 +63,11 @@ void GraphItem::setColor(const QColor &color)
void GraphItem::setWidth(int width)
{
if (width == _width)
if (width == _pen.width())
return;
prepareGeometryChange();
_width = width;
_pen.setWidth(width);
updateShape();
@ -170,10 +163,10 @@ void GraphItem::emitSliderPositionChanged(qreal pos)
void GraphItem::hover(bool hover)
{
if (hover) {
_pen.setWidth(_width + 1);
_pen.setWidth(_pen.width() + 1);
setZValue(zValue() + 1.0);
} else {
_pen.setWidth(_width);
_pen.setWidth(_pen.width() - 1);
setZValue(zValue() - 1.0);
}
@ -189,23 +182,30 @@ void GraphItem::setScale(qreal sx, qreal sy)
_sx = sx; _sy = sy;
updatePath();
updateShape();
}
void GraphItem::updatePath()
{
_path = QPainterPath();
if (_type == Time && !_time)
if (_sx == 0 && _sy == 0)
return;
for (int i = 0; i < _graph.size(); i++) {
const GraphSegment &segment = _graph.at(i);
prepareGeometryChange();
_path.moveTo(segment.first().x(_type) * _sx, -segment.first().y() * _sy);
for (int i = 1; i < segment.size(); i++)
_path.lineTo(segment.at(i).x(_type) * _sx, -segment.at(i).y() * _sy);
_path = QPainterPath();
if (!(_type == Time && !_time)) {
for (int i = 0; i < _graph.size(); i++) {
const GraphSegment &segment = _graph.at(i);
_path.moveTo(segment.first().x(_type) * _sx, -segment.first().y()
* _sy);
for (int i = 1; i < segment.size(); i++)
_path.lineTo(segment.at(i).x(_type) * _sx, -segment.at(i).y()
* _sy);
}
}
updateShape();
}
void GraphItem::updateBounds()
@ -286,7 +286,7 @@ void GraphItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event);
_pen.setWidthF(_width + 1);
_pen.setWidth(_pen.width() + 1);
setZValue(zValue() + 1.0);
update();
@ -297,7 +297,7 @@ void GraphItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event);
_pen.setWidthF(_width);
_pen.setWidth(_pen.width() - 1);
setZValue(zValue() - 1.0);
update();

View File

@ -11,7 +11,8 @@ class GraphItem : public QGraphicsObject
Q_OBJECT
public:
GraphItem(const Graph &graph, GraphType type, QGraphicsItem *parent = 0);
GraphItem(const Graph &graph, GraphType type, int width, const QColor &color,
QGraphicsItem *parent = 0);
virtual ~GraphItem() {}
QPainterPath shape() const {return _shape;}
@ -27,8 +28,6 @@ public:
void setScale(qreal sx, qreal sy);
void setGraphType(GraphType type);
int id() const {return _id;}
void setId(int id) {_id = id;}
void setColor(const QColor &color);
void setWidth(int width);
virtual void setUnits(Units units) {Q_UNUSED(units);}
@ -55,17 +54,13 @@ private:
void updateShape();
void updateBounds();
int _id;
QPen _pen;
int _width;
Graph _graph;
GraphType _type;
QPainterPath _path;
QPainterPath _shape;
QRectF _bounds;
qreal _sx, _sy;
QPen _pen;
bool _time;
};

View File

@ -1,8 +1,7 @@
#include <QGraphicsScene>
#include <QEvent>
#include <QMouseEvent>
#include <QPaintEngine>
#include <QPaintDevice>
#include <QScrollBar>
#include <QGraphicsSimpleTextItem>
#include <QPalette>
#include <QLocale>
@ -64,6 +63,8 @@ GraphView::GraphView(QWidget *parent)
_units = Metric;
_graphType = Distance;
_xLabel = tr("Distance");
_zoom = 1.0;
}
GraphView::~GraphView()
@ -74,8 +75,6 @@ GraphView::~GraphView()
delete _info;
delete _grid;
delete _message;
qDeleteAll(_graphs);
}
void GraphView::createXLabel()
@ -166,14 +165,7 @@ void GraphView::setGraphType(GraphType type)
for (int i = 0; i < _graphs.count(); i++) {
GraphItem *gi = _graphs.at(i);
gi->setGraphType(type);
if (!_hide.contains(gi->id())) {
if (gi->bounds().width() > 0)
addItem(gi);
else
removeItem(gi);
}
if (gi->scene() == _scene)
_bounds |= gi->bounds();
_bounds |= gi->bounds();
}
if (type == Distance)
@ -195,29 +187,31 @@ void GraphView::showSliderInfo(bool show)
_sliderInfo->setVisible(show);
}
void GraphView::addGraph(GraphItem *graph, int id)
void GraphView::addGraph(GraphItem *graph)
{
QColor color(_palette.nextColor());
color.setAlpha(255);
graph->setUnits(_units);
graph->setId(id);
graph->setColor(color);
graph->setWidth(_width);
connect(this, SIGNAL(sliderPositionChanged(qreal)), graph,
SLOT(emitSliderPositionChanged(qreal)));
_graphs.append(graph);
_scene->addItem(graph);
_bounds |= graph->bounds();
if (!_hide.contains(id)) {
_visible.append(graph);
if (graph->bounds().width() > 0) {
_scene->addItem(graph);
_bounds |= graph->bounds();
}
setXUnits();
}
setXUnits();
}
void GraphView::removeGraph(GraphItem *graph)
{
disconnect(this, SIGNAL(sliderPositionChanged(qreal)), graph,
SLOT(emitSliderPositionChanged(qreal)));
_graphs.removeOne(graph);
_scene->removeItem(graph);
_bounds = QRectF();
for (int i = 0; i < _graphs.count(); i++)
_bounds |= _graphs.at(i)->bounds();
setXUnits();
}
void GraphView::removeItem(QGraphicsItem *item)
@ -232,29 +226,6 @@ void GraphView::addItem(QGraphicsItem *item)
_scene->addItem(item);
}
void GraphView::showGraph(bool show, int id)
{
if (show)
_hide.remove(id);
else
_hide.insert(id);
_visible.clear();
_bounds = QRectF();
for (int i = 0; i < _graphs.count(); i++) {
GraphItem *gi = _graphs.at(i);
if (_hide.contains(gi->id()))
removeItem(gi);
else {
_visible.append(gi);
if (gi->bounds().width() > 0) {
addItem(gi);
_bounds |= gi->bounds();
}
}
}
}
QRectF GraphView::bounds() const
{
QRectF br(_bounds);
@ -313,9 +284,10 @@ void GraphView::redraw(const QSizeF &size)
sx = (size.width() - (my.width() + mx.width())) / r.width();
sy = (size.height() - (mx.height() + my.height())
- _info->boundingRect().height()) / r.height();
sx *= _zoom;
for (int i = 0; i < _visible.size(); i++)
_visible.at(i)->setScale(sx, sy);
for (int i = 0; i < _graphs.size(); i++)
_graphs.at(i)->setScale(sx, sy);
QPointF p(r.left() * sx, r.top() * sy);
QSizeF s(r.width() * sx, r.height() * sy);
@ -360,6 +332,40 @@ void GraphView::mousePressEvent(QMouseEvent *e)
QGraphicsView::mousePressEvent(e);
}
void GraphView::wheelEvent(QWheelEvent *e)
{
static int deg = 0;
deg += e->delta() / 8;
if (qAbs(deg) < 15)
return;
deg = 0;
QPointF pos = mapToScene(e->pos());
QRectF gr(_grid->boundingRect());
QPointF r(pos.x() / gr.width(), pos.y() / gr.height());
_zoom = (e->delta() > 0) ? _zoom * 1.25 : qMax(_zoom / 1.25, 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() - e->pos().x());
QGraphicsView::wheelEvent(e);
}
void GraphView::paintEvent(QPaintEvent *event)
{
QRectF viewRect(mapToScene(rect()).boundingRect());
_info->setPos(QPointF(viewRect.left() + (viewRect.width()
- _info->boundingRect().width())/2.0, _info->pos().y()));
QGraphicsView::paintEvent(event);
}
void GraphView::plot(QPainter *painter, const QRectF &target, qreal scale)
{
QSizeF canvas = QSizeF(target.width() / scale, target.height() / scale);
@ -376,54 +382,45 @@ void GraphView::plot(QPainter *painter, const QRectF &target, qreal scale)
void GraphView::clear()
{
_graphs.clear();
_slider->clear();
_info->clear();
qDeleteAll(_graphs);
_graphs.clear();
_visible.clear();
_palette.reset();
_bounds = QRectF();
_sliderPos = 0;
_zoom = 1.0;
_scene->setSceneRect(0, 0, 0, 0);
}
void GraphView::updateSliderPosition()
{
if (bounds().width() <= 0)
return;
if (_sliderPos <= bounds().right() && _sliderPos >= bounds().left()) {
_slider->setPos((_sliderPos / bounds().width())
* _slider->area().width(), _slider->area().bottom());
_slider->setVisible(!_visible.isEmpty());
_slider->setVisible(true);
updateSliderInfo();
} else {
_slider->setPos(_slider->area().left(), _slider->area().bottom());
_slider->setVisible(false);
}
if (_slider->isVisible())
updateSliderInfo();
}
void GraphView::updateSliderInfo()
{
QLocale l(QLocale::system());
qreal r, y;
qreal r = 0, y = 0;
if (_visible.count() > 1) {
r = 0;
y = 0;
} else {
QRectF br(_visible.first()->bounds());
if (_graphs.count() == 1) {
QRectF br(_graphs.first()->bounds());
if (br.height() < _minYRange)
br.adjust(0, -(_minYRange/2 - br.height()/2), 0,
_minYRange/2 - br.height()/2);
y = _visible.first()->yAtX(_sliderPos);
y = _graphs.first()->yAtX(_sliderPos);
r = (y - br.bottom()) / br.height();
}
@ -435,7 +432,7 @@ void GraphView::updateSliderInfo()
_sliderInfo->setPos(QPointF(0, _slider->boundingRect().height() * r));
_sliderInfo->setText(_graphType == Time ? Format::timeSpan(_sliderPos,
bounds().width() > 3600) : l.toString(_sliderPos * _xScale, 'f', 1)
+ UNIT_SPACE + _xUnits, (_visible.count() > 1) ? QString()
+ UNIT_SPACE + _xUnits, (_graphs.count() > 1) ? QString()
: l.toString(-y * _yScale + _yOffset, 'f', _precision) + UNIT_SPACE
+ _yUnits);
}
@ -455,7 +452,7 @@ void GraphView::emitSliderPositionChanged(const QPointF &pos)
void GraphView::setSliderPosition(qreal pos)
{
if (_visible.isEmpty())
if (_graphs.isEmpty())
return;
_sliderPos = pos;
@ -483,11 +480,8 @@ void GraphView::setPalette(const Palette &palette)
_palette = palette;
_palette.reset();
for (int i = 0; i < _graphs.count(); i++) {
QColor color(_palette.nextColor());
color.setAlpha(255);
_graphs.at(i)->setColor(color);
}
for (int i = 0; i < _graphs.count(); i++)
_graphs.at(i)->setColor(_palette.nextColor());
}
void GraphView::setGraphWidth(int width)

View File

@ -27,7 +27,7 @@ public:
~GraphView();
bool isEmpty() const {return _graphs.isEmpty();}
const QList<KV> &info() const {return _info->info();}
const QList<KV<QString, QString> > &info() const {return _info->info();}
void clear();
void plot(QPainter *painter, const QRectF &target, qreal scale);
@ -46,9 +46,9 @@ signals:
void sliderPositionChanged(qreal);
protected:
void addGraph(GraphItem *graph, int id = 0);
void addGraph(GraphItem *graph);
void removeGraph(GraphItem *graph);
void showGraph(bool show, int id = 0);
void setGraphType(GraphType type);
void setUnits(Units units);
@ -68,12 +68,11 @@ protected:
void redraw();
void addInfo(const QString &key, const QString &value);
void clearInfo();
void skipColor() {_palette.nextColor();}
void changeEvent(QEvent *e);
QList<GraphItem*> _graphs;
GraphType _graphType;
Units _units;
Palette _palette;
int _width;
private slots:
void emitSliderPositionChanged(const QPointF &pos);
@ -91,15 +90,9 @@ private:
void resizeEvent(QResizeEvent *e);
void mousePressEvent(QMouseEvent *e);
Units _units;
qreal _xScale, _yScale;
qreal _yOffset;
QString _xUnits, _yUnits;
QString _xLabel, _yLabel;
int _precision;
qreal _minYRange;
qreal _sliderPos;
void wheelEvent(QWheelEvent *e);
void changeEvent(QEvent *e);
void paintEvent(QPaintEvent *event);
QGraphicsScene *_scene;
@ -109,12 +102,19 @@ private:
InfoItem *_info;
GridItem *_grid;
QGraphicsSimpleTextItem *_message;
QList<GraphItem*> _graphs;
QList<GraphItem*> _visible;
QSet<int> _hide;
QRectF _bounds;
Palette _palette;
int _width;
qreal _sliderPos;
qreal _xScale, _yScale;
qreal _yOffset;
QString _xUnits, _yUnits;
QString _xLabel, _yLabel;
int _precision;
qreal _minYRange;
qreal _zoom;
};
#endif // GRAPHVIEW_H

View File

@ -1066,7 +1066,7 @@ void GUI::statistics()
text.append("<tr><th colspan=\"2\">" + tab->label() + "</th></tr>");
for (int j = 0; j < tab->info().size(); j++) {
const KV &kv = tab->info().at(j);
const KV<QString, QString> &kv = tab->info().at(j);
text.append("<tr><td>" + kv.key() + ":</td><td>" + kv.value()
+ "</td></tr>");
}

View File

@ -14,6 +14,11 @@ HeartRateGraph::HeartRateGraph(QWidget *parent) : GraphTab(parent)
setSliderPrecision(0);
}
HeartRateGraph::~HeartRateGraph()
{
qDeleteAll(_tracks);
}
void HeartRateGraph::setInfo()
{
if (_showTracks) {
@ -36,23 +41,28 @@ QList<GraphItem*> HeartRateGraph::loadData(const Data &data)
const Graph &graph = track.heartRate();
if (!graph.isValid()) {
skipColor();
_palette.nextColor();
graphs.append(0);
} else {
HeartRateGraphItem *gi = new HeartRateGraphItem(graph, _graphType);
GraphView::addGraph(gi);
HeartRateGraphItem *gi = new HeartRateGraphItem(graph, _graphType,
_width, _palette.nextColor());
_tracks.append(gi);
if (_showTracks)
addGraph(gi);
_avg.append(QPointF(track.distance(), gi->avg()));
graphs.append(gi);
}
}
for (int i = 0; i < data.routes().count(); i++) {
skipColor();
_palette.nextColor();
graphs.append(0);
}
for (int i = 0; i < data.areas().count(); i++)
skipColor();
_palette.nextColor();
setInfo();
redraw();
@ -75,6 +85,9 @@ qreal HeartRateGraph::avg() const
void HeartRateGraph::clear()
{
qDeleteAll(_tracks);
_tracks.clear();
_avg.clear();
GraphTab::clear();
@ -84,7 +97,13 @@ void HeartRateGraph::showTracks(bool show)
{
_showTracks = show;
showGraph(show);
for (int i = 0; i < _tracks.size(); i++) {
if (show)
addGraph(_tracks.at(i));
else
removeGraph(_tracks.at(i));
}
setInfo();
redraw();

View File

@ -3,12 +3,15 @@
#include "graphtab.h"
class HeartRateGraphItem;
class HeartRateGraph : public GraphTab
{
Q_OBJECT
public:
HeartRateGraph(QWidget *parent = 0);
~HeartRateGraph();
QString label() const {return tr("Heart rate");}
QList<GraphItem*> loadData(const Data &data);
@ -23,6 +26,7 @@ private:
QVector<QPointF> _avg;
bool _showTracks;
QList<HeartRateGraphItem*> _tracks;
};
#endif // HEARTRATEGRAPH_H

View File

@ -4,7 +4,8 @@
HeartRateGraphItem::HeartRateGraphItem(const Graph &graph, GraphType type,
QGraphicsItem *parent) : GraphItem(graph, type, parent)
int width, const QColor &color, QGraphicsItem *parent)
: GraphItem(graph, type, width, color, parent)
{
setToolTip(toolTip());
}

View File

@ -8,8 +8,8 @@ class HeartRateGraphItem : public GraphItem
Q_OBJECT
public:
HeartRateGraphItem(const Graph &graph, GraphType type,
QGraphicsItem *parent = 0);
HeartRateGraphItem(const Graph &graph, GraphType type, int width,
const QColor &color, QGraphicsItem *parent = 0);
private:
QString toolTip() const;

View File

@ -16,7 +16,7 @@ void InfoItem::updateBoundingRect()
QFontMetrics fm(_font);
qreal width = 0;
for (QList<KV>::const_iterator i = _list.constBegin();
for (QList<KV<QString, QString> >::const_iterator i = _list.constBegin();
i != _list.constEnd(); i++) {
width += fm.width(i->key() + ": ");
width += fm.width(i->value()) + ((i == _list.constEnd() - 1)
@ -37,7 +37,7 @@ void InfoItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
painter->setFont(_font);
painter->setRenderHint(QPainter::Antialiasing, false);
for (QList<KV>::const_iterator i = _list.constBegin();
for (QList<KV<QString, QString> >::const_iterator i = _list.constBegin();
i != _list.constEnd(); i++) {
painter->drawText(width, fm.height() - fm.descent(), i->key() + ": ");
width += fm.width(i->key() + ": ");
@ -61,7 +61,7 @@ void InfoItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
void InfoItem::insert(const QString &key, const QString &value)
{
KV kv(key, value);
KV<QString, QString> kv(key, value);
int i;
prepareGeometryChange();

View File

@ -14,7 +14,7 @@ public:
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget);
const QList<KV> &info() const {return _list;}
const QList<KV<QString, QString> > &info() const {return _list;}
void insert(const QString &key, const QString &value);
void clear();
@ -23,7 +23,7 @@ public:
private:
void updateBoundingRect();
QList<KV> _list;
QList<KV<QString, QString> > _list;
QRectF _boundingRect;
QFont _font;
};

View File

@ -255,17 +255,18 @@ QPointF MapView::contentCenter() const
void MapView::updatePOIVisibility()
{
QHash<SearchPointer<Waypoint>, WaypointItem*>::const_iterator it, jt;
if (!_showPOI)
return;
for (it = _pois.constBegin(); it != _pois.constEnd(); it++)
for (POIHash::const_iterator it = _pois.constBegin();
it != _pois.constEnd(); it++)
it.value()->show();
if (!_overlapPOIs) {
for (it = _pois.constBegin(); it != _pois.constEnd(); it++) {
for (jt = _pois.constBegin(); jt != _pois.constEnd(); jt++) {
for (POIHash::const_iterator it = _pois.constBegin();
it != _pois.constEnd(); it++) {
for (POIHash::const_iterator jt = _pois.constBegin();
jt != _pois.constEnd(); jt++) {
if (it.value()->isVisible() && jt.value()->isVisible()
&& it != jt && it.value()->collidesWithItem(jt.value()))
jt.value()->hide();
@ -288,8 +289,8 @@ void MapView::rescale()
for (int i = 0; i < _waypoints.size(); i++)
_waypoints.at(i)->setMap(_map);
QHash<SearchPointer<Waypoint>, WaypointItem*>::const_iterator it;
for (it = _pois.constBegin(); it != _pois.constEnd(); it++)
for (POIHash::const_iterator it = _pois.constBegin();
it != _pois.constEnd(); it++)
it.value()->setMap(_map);
updatePOIVisibility();
@ -339,8 +340,8 @@ void MapView::setMap(Map *map)
for (int i = 0; i < _waypoints.size(); i++)
_waypoints.at(i)->setMap(map);
QHash<SearchPointer<Waypoint>, WaypointItem*>::const_iterator it;
for (it = _pois.constBegin(); it != _pois.constEnd(); it++)
for (POIHash::const_iterator it = _pois.constBegin();
it != _pois.constEnd(); it++)
it.value()->setMap(_map);
updatePOIVisibility();
@ -364,12 +365,10 @@ void MapView::setPOI(POI *poi)
void MapView::updatePOI()
{
QHash<SearchPointer<Waypoint>, WaypointItem*>::const_iterator it;
for (it = _pois.constBegin(); it != _pois.constEnd(); it++) {
for (POIHash::const_iterator it = _pois.constBegin();
it != _pois.constEnd(); it++)
_scene->removeItem(it.value());
delete it.value();
}
qDeleteAll(_pois);
_pois.clear();
if (_showTracks)
@ -426,8 +425,8 @@ void MapView::setUnits(Units units)
for (int i = 0; i < _waypoints.size(); i++)
_waypoints.at(i)->setToolTipFormat(_units, _coordinatesFormat);
QHash<SearchPointer<Waypoint>, WaypointItem*>::const_iterator it;
for (it = _pois.constBegin(); it != _pois.constEnd(); it++)
for (POIHash::const_iterator it = _pois.constBegin();
it != _pois.constEnd(); it++)
it.value()->setToolTipFormat(_units, _coordinatesFormat);
}
@ -445,8 +444,8 @@ void MapView::setCoordinatesFormat(CoordinatesFormat format)
for (int i = 0; i < _routes.count(); i++)
_routes[i]->setCoordinatesFormat(_coordinatesFormat);
QHash<SearchPointer<Waypoint>, WaypointItem*>::const_iterator it;
for (it = _pois.constBegin(); it != _pois.constEnd(); it++)
for (POIHash::const_iterator it = _pois.constBegin();
it != _pois.constEnd(); it++)
it.value()->setToolTipFormat(_units, _coordinatesFormat);
}
@ -461,8 +460,6 @@ void MapView::clearMapCache()
void MapView::digitalZoom(int zoom)
{
QHash<SearchPointer<Waypoint>, WaypointItem*>::const_iterator it;
if (zoom) {
_digitalZoom += zoom;
scale(pow(2, zoom), pow(2, zoom));
@ -479,7 +476,8 @@ void MapView::digitalZoom(int zoom)
_areas.at(i)->setDigitalZoom(_digitalZoom);
for (int i = 0; i < _waypoints.size(); i++)
_waypoints.at(i)->setDigitalZoom(_digitalZoom);
for (it = _pois.constBegin(); it != _pois.constEnd(); it++)
for (POIHash::const_iterator it = _pois.constBegin();
it != _pois.constEnd(); it++)
it.value()->setDigitalZoom(_digitalZoom);
_mapScale->setDigitalZoom(_digitalZoom);
@ -747,8 +745,8 @@ void MapView::showPOI(bool show)
{
_showPOI = show;
QHash<SearchPointer<Waypoint>, WaypointItem*>::const_iterator it;
for (it = _pois.constBegin(); it != _pois.constEnd(); it++)
for (POIHash::const_iterator it = _pois.constBegin();
it != _pois.constEnd(); it++)
it.value()->setVisible(show);
updatePOIVisibility();
@ -758,8 +756,8 @@ void MapView::showPOILabels(bool show)
{
_showPOILabels = show;
QHash<SearchPointer<Waypoint>, WaypointItem*>::const_iterator it;
for (it = _pois.constBegin(); it != _pois.constEnd(); it++)
for (POIHash::const_iterator it = _pois.constBegin();
it != _pois.constEnd(); it++)
it.value()->showLabel(show);
updatePOIVisibility();
@ -852,21 +850,19 @@ void MapView::setWaypointColor(const QColor &color)
void MapView::setPOISize(int size)
{
QHash<SearchPointer<Waypoint>, WaypointItem*>::const_iterator it;
_poiSize = size;
for (it = _pois.constBegin(); it != _pois.constEnd(); it++)
for (POIHash::const_iterator it = _pois.constBegin();
it != _pois.constEnd(); it++)
it.value()->setSize(size);
}
void MapView::setPOIColor(const QColor &color)
{
QHash<SearchPointer<Waypoint>, WaypointItem*>::const_iterator it;
_poiColor = color;
for (it = _pois.constBegin(); it != _pois.constEnd(); it++)
for (POIHash::const_iterator it = _pois.constBegin();
it != _pois.constEnd(); it++)
it.value()->setColor(color);
}
@ -1003,8 +999,8 @@ void MapView::setDevicePixelRatio(qreal deviceRatio, qreal mapRatio)
for (int i = 0; i < _waypoints.size(); i++)
_waypoints.at(i)->setMap(_map);
QHash<SearchPointer<Waypoint>, WaypointItem*>::const_iterator it;
for (it = _pois.constBegin(); it != _pois.constEnd(); it++)
for (POIHash::const_iterator it = _pois.constBegin();
it != _pois.constEnd(); it++)
it.value()->setMap(_map);
updatePOIVisibility();
@ -1021,13 +1017,17 @@ void MapView::setDevicePixelRatio(qreal deviceRatio, qreal mapRatio)
void MapView::setProjection(int id)
{
Projection projection(PCS::pcs(id));
if (!projection.isValid())
return;
_projection = projection;
const PCS *pcs;
const GCS *gcs;
Coordinates center = _map->xy2ll(mapToScene(viewport()->rect().center()));
if ((pcs = PCS::pcs(id)))
_projection = Projection(pcs);
else if ((gcs = GCS::gcs(id)))
_projection = Projection(gcs);
else
qWarning("%d: Unknown PCS/GCS id", id);
_map->setProjection(_projection);
rescale();
centerOn(_map->ll2xy(center));

View File

@ -92,6 +92,8 @@ private slots:
void reloadMap();
private:
typedef QHash<SearchPointer<Waypoint>, WaypointItem*> POIHash;
PathItem *addTrack(const Track &track);
PathItem *addRoute(const Route &route);
void addArea(const Area &area);
@ -125,7 +127,7 @@ private:
QList<RouteItem*> _routes;
QList<WaypointItem*> _waypoints;
QList<AreaItem*> _areas;
QHash<SearchPointer<Waypoint>, WaypointItem*> _pois;
POIHash _pois;
RectC _tr, _rr, _wr, _ar;
qreal _res;

View File

@ -36,15 +36,18 @@ static QFrame *line()
}
#endif // Q_OS_MAC
QWidget *OptionsDialog::createMapPage()
{
_projection = new LimitedComboBox(200);
QList<PCS::Info> projections(PCS::pcsList());
QList<KV<int, QString> > projections(GCS::list() + PCS::list());
qSort(projections);
for (int i = 0; i < projections.size(); i++) {
QString text = QString::number(projections.at(i).id()) + " - "
+ projections.at(i).name();
_projection->addItem(text, QVariant(projections.at(i).id()));
QString text = QString::number(projections.at(i).key()) + " - "
+ projections.at(i).value();
_projection->addItem(text, QVariant(projections.at(i).key()));
}
_projection->setCurrentIndex(_projection->findData(_options->projection));

View File

@ -24,7 +24,7 @@ PercentSlider::PercentSlider(QWidget *parent) : QWidget(parent)
_label->setAlignment(Qt::AlignRight);
_label->setText(format(_slider->value()));
connect(_slider, SIGNAL(sliderMoved(int)), this, SLOT(updateLabel(int)));
connect(_slider, SIGNAL(valueChanged(int)), this, SLOT(updateLabel(int)));
QHBoxLayout *layout = new QHBoxLayout();
layout->addWidget(_slider);

View File

@ -14,6 +14,11 @@ PowerGraph::PowerGraph(QWidget *parent) : GraphTab(parent)
setSliderPrecision(1);
}
PowerGraph::~PowerGraph()
{
qDeleteAll(_tracks);
}
void PowerGraph::setInfo()
{
if (_showTracks) {
@ -36,23 +41,27 @@ QList<GraphItem*> PowerGraph::loadData(const Data &data)
const Graph &graph = track.power();
if (!graph.isValid()) {
skipColor();
_palette.nextColor();
graphs.append(0);
} else {
PowerGraphItem *gi = new PowerGraphItem(graph, _graphType);
GraphView::addGraph(gi);
PowerGraphItem *gi = new PowerGraphItem(graph, _graphType, _width,
_palette.nextColor());
_tracks.append(gi);
if (_showTracks)
addGraph(gi);
_avg.append(QPointF(track.distance(), gi->avg()));
graphs.append(gi);
}
}
for (int i = 0; i < data.routes().count(); i++) {
skipColor();
_palette.nextColor();
graphs.append(0);
}
for (int i = 0; i < data.areas().count(); i++)
skipColor();
_palette.nextColor();
setInfo();
redraw();
@ -75,6 +84,9 @@ qreal PowerGraph::avg() const
void PowerGraph::clear()
{
qDeleteAll(_tracks);
_tracks.clear();
_avg.clear();
GraphTab::clear();
@ -84,7 +96,13 @@ void PowerGraph::showTracks(bool show)
{
_showTracks = show;
showGraph(show);
for (int i = 0; i < _tracks.size(); i++) {
if (show)
addGraph(_tracks.at(i));
else
removeGraph(_tracks.at(i));
}
setInfo();
redraw();

View File

@ -3,12 +3,15 @@
#include "graphtab.h"
class PowerGraphItem;
class PowerGraph : public GraphTab
{
Q_OBJECT
public:
PowerGraph(QWidget *parent = 0);
~PowerGraph();
QString label() const {return tr("Power");}
QList<GraphItem*> loadData(const Data &data);
@ -23,6 +26,7 @@ private:
QVector<QPointF> _avg;
bool _showTracks;
QList<PowerGraphItem*> _tracks;
};
#endif // POWERGRAPH_H

View File

@ -3,8 +3,9 @@
#include "powergraphitem.h"
PowerGraphItem::PowerGraphItem(const Graph &graph, GraphType type,
QGraphicsItem *parent) : GraphItem(graph, type, parent)
PowerGraphItem::PowerGraphItem(const Graph &graph, GraphType type, int width,
const QColor &color, QGraphicsItem *parent)
: GraphItem(graph, type, width, color, parent)
{
setToolTip(toolTip());
}

View File

@ -8,8 +8,8 @@ class PowerGraphItem : public GraphItem
Q_OBJECT
public:
PowerGraphItem(const Graph &graph, GraphType type,
QGraphicsItem *parent = 0);
PowerGraphItem(const Graph &graph, GraphType type, int width,
const QColor &color, QGraphicsItem *parent = 0);
private:
QString toolTip() const;

View File

@ -24,7 +24,7 @@ QString RouteItem::toolTip(Units units) const
RouteItem::RouteItem(const Route &route, Map *map, QGraphicsItem *parent)
: PathItem(route.path(), map, parent)
{
const QVector<Waypoint> &waypoints = route.waypoints();
const RouteData &waypoints = route.data();
_waypoints.resize(waypoints.size());
for (int i = 0; i < waypoints.size(); i++)

View File

@ -152,7 +152,7 @@
#define ENABLE_HTTP2_SETTING "enableHTTP2"
#define ENABLE_HTTP2_DEFAULT true
#define PIXMAP_CACHE_SETTING "pixmapCache"
#define PIXMAP_CACHE_DEFAULT 64 /* MB */
#define PIXMAP_CACHE_DEFAULT 256 /* MB */
#define CONNECTION_TIMEOUT_SETTING "connectionTimeout"
#define CONNECTION_TIMEOUT_DEFAULT 30 /* s */
#define HIRES_PRINT_SETTING "hiresPrint"

View File

@ -18,6 +18,11 @@ SpeedGraph::SpeedGraph(QWidget *parent) : GraphTab(parent)
setSliderPrecision(1);
}
SpeedGraph::~SpeedGraph()
{
qDeleteAll(_tracks);
}
void SpeedGraph::setInfo()
{
if (_showTracks) {
@ -44,13 +49,18 @@ QList<GraphItem*> SpeedGraph::loadData(const Data &data)
const Graph &graph = track.speed();
if (!graph.isValid()) {
skipColor();
_palette.nextColor();
graphs.append(0);
} else {
SpeedGraphItem *gi = new SpeedGraphItem(graph, _graphType,
track.movingTime());
SpeedGraphItem *gi = new SpeedGraphItem(graph, _graphType, _width,
_palette.nextColor(), track.movingTime());
gi->setTimeType(_timeType);
GraphView::addGraph(gi);
gi->setUnits(_units);
_tracks.append(gi);
if (_showTracks)
addGraph(gi);
_avg.append(QPointF(track.distance(), gi->avg()));
_mavg.append(QPointF(track.distance(), gi->mavg()));
graphs.append(gi);
@ -58,12 +68,12 @@ QList<GraphItem*> SpeedGraph::loadData(const Data &data)
}
for (int i = 0; i < data.routes().count(); i++) {
skipColor();
_palette.nextColor();
graphs.append(0);
}
for (int i = 0; i < data.areas().count(); i++)
skipColor();
_palette.nextColor();
setInfo();
redraw();
@ -87,6 +97,9 @@ qreal SpeedGraph::avg() const
void SpeedGraph::clear()
{
qDeleteAll(_tracks);
_tracks.clear();
_avg.clear();
_mavg.clear();
@ -121,8 +134,8 @@ void SpeedGraph::setTimeType(enum TimeType type)
{
_timeType = type;
for (int i = 0; i < _graphs.size(); i++)
static_cast<SpeedGraphItem*>(_graphs.at(i))->setTimeType(type);
for (int i = 0; i < _tracks.size(); i++)
_tracks.at(i)->setTimeType(type);
setInfo();
redraw();
@ -132,7 +145,13 @@ void SpeedGraph::showTracks(bool show)
{
_showTracks = show;
showGraph(show);
for (int i = 0; i < _tracks.size(); i++) {
if (show)
addGraph(_tracks.at(i));
else
removeGraph(_tracks.at(i));
}
setInfo();
redraw();

View File

@ -4,12 +4,15 @@
#include <QList>
#include "graphtab.h"
class SpeedGraphItem;
class SpeedGraph : public GraphTab
{
Q_OBJECT
public:
SpeedGraph(QWidget *parent = 0);
~SpeedGraph();
QString label() const {return tr("Speed");}
QList<GraphItem*> loadData(const Data &data);
@ -29,7 +32,9 @@ private:
Units _units;
TimeType _timeType;
bool _showTracks;
QList<SpeedGraphItem *> _tracks;
};
#endif // SPEEDGRAPH_H

View File

@ -4,8 +4,9 @@
#include "speedgraphitem.h"
SpeedGraphItem::SpeedGraphItem(const Graph &graph, GraphType type,
qreal movingTime, QGraphicsItem *parent) : GraphItem(graph, type, parent)
SpeedGraphItem::SpeedGraphItem(const Graph &graph, GraphType type, int width,
const QColor &color, qreal movingTime, QGraphicsItem *parent)
: GraphItem(graph, type, width, color, parent)
{
_units = Metric;
_timeType = Total;

View File

@ -9,8 +9,8 @@ class SpeedGraphItem : public GraphItem
Q_OBJECT
public:
SpeedGraphItem(const Graph &graph, GraphType type, qreal movingTime,
QGraphicsItem *parent = 0);
SpeedGraphItem(const Graph &graph, GraphType type, int width,
const QColor &color, qreal movingTime, QGraphicsItem *parent = 0);
qreal avg() const {return _avg;}
qreal mavg() const {return _mavg;}
@ -23,9 +23,8 @@ private:
QString toolTip() const;
qreal _avg, _mavg, _max;
Units _units;
TimeType _timeType;
Units _units;
};
#endif // SPEEDGRAPHITEM_H

View File

@ -14,6 +14,11 @@ TemperatureGraph::TemperatureGraph(QWidget *parent) : GraphTab(parent)
setSliderPrecision(1);
}
TemperatureGraph::~TemperatureGraph()
{
qDeleteAll(_tracks);
}
void TemperatureGraph::setInfo()
{
if (_showTracks) {
@ -38,24 +43,29 @@ QList<GraphItem*> TemperatureGraph::loadData(const Data &data)
const Graph &graph = track.temperature();
if (!graph.isValid()) {
skipColor();
_palette.nextColor();
graphs.append(0);
} else {
TemperatureGraphItem *gi = new TemperatureGraphItem(graph,
_graphType);
GraphView::addGraph(gi);
_graphType, _width, _palette.nextColor());
gi->setUnits(_units);
_tracks.append(gi);
if (_showTracks)
addGraph(gi);
_avg.append(QPointF(track.distance(), gi->avg()));
graphs.append(gi);
}
}
for (int i = 0; i < data.routes().count(); i++) {
skipColor();
_palette.nextColor();
graphs.append(0);
}
for (int i = 0; i < data.areas().count(); i++)
skipColor();
_palette.nextColor();
setInfo();
redraw();
@ -78,6 +88,9 @@ qreal TemperatureGraph::avg() const
void TemperatureGraph::clear()
{
qDeleteAll(_tracks);
_tracks.clear();
_avg.clear();
GraphTab::clear();
@ -108,7 +121,13 @@ void TemperatureGraph::showTracks(bool show)
{
_showTracks = show;
showGraph(show);
for (int i = 0; i < _tracks.size(); i++) {
if (show)
addGraph(_tracks.at(i));
else
removeGraph(_tracks.at(i));
}
setInfo();
redraw();

View File

@ -3,12 +3,15 @@
#include "graphtab.h"
class TemperatureGraphItem;
class TemperatureGraph : public GraphTab
{
Q_OBJECT
public:
TemperatureGraph(QWidget *parent = 0);
~TemperatureGraph();
QString label() const {return tr("Temperature");}
QList<GraphItem*> loadData(const Data &data);
@ -26,6 +29,7 @@ private:
QVector<QPointF> _avg;
bool _showTracks;
QList<TemperatureGraphItem *> _tracks;
};
#endif // TEMPERATUREGRAPH_H

View File

@ -4,7 +4,8 @@
TemperatureGraphItem::TemperatureGraphItem(const Graph &graph, GraphType type,
QGraphicsItem *parent) : GraphItem(graph, type, parent)
int width, const QColor &color, QGraphicsItem *parent)
: GraphItem(graph, type, width, color, parent)
{
_min = GraphItem::min();
_max = GraphItem::max();

View File

@ -8,8 +8,8 @@ class TemperatureGraphItem : public GraphItem
Q_OBJECT
public:
TemperatureGraphItem(const Graph &graph, GraphType type,
QGraphicsItem *parent = 0);
TemperatureGraphItem(const Graph &graph, GraphType type, int width,
const QColor &color, QGraphicsItem *parent = 0);
qreal max() const {return _max;}
qreal min() const {return _min;}

View File

@ -6,7 +6,7 @@
void ToolTip::insert(const QString &key, const QString &value)
{
_list.append(KV(key, value));
_list.append(KV<QString, QString>(key, value));
}
QString ToolTip::toString() const

View File

@ -14,7 +14,7 @@ public:
QString toString() const;
private:
QList<KV> _list;
QList<KV<QString, QString> > _list;
ImageInfo _img;
};

View File

@ -1,21 +1,20 @@
#ifndef KV_H
#define KV_H
#include <QString>
template <class KEY, class VALUE>
class KV {
public:
KV(const QString &key, const QString &value) : _key(key), _value(value) {}
KV(const KEY &key, const VALUE &value) : _key(key), _value(value) {}
const QString &key() const {return _key;}
const QString &value() const {return _value;}
const KEY &key() const {return _key;}
const VALUE &value() const {return _value;}
bool operator==(const KV &other) const
{return this->key() == other.key();}
bool operator==(const KV &other) const {return _key == other._key;}
bool operator<(const KV &other) const {return _key < other._key;}
private:
QString _key;
QString _value;
KEY _key;
VALUE _value;
};
#endif // KV_H

View File

@ -17,6 +17,7 @@ public:
TIFFFile(QIODevice *device);
bool isValid() const {return _ifd != 0;}
bool isBE() const {return _be;}
quint32 ifd() const {return _ifd;}
bool seek(qint64 pos) {return _device->seek(_offset + pos);}

67
src/data/csv.cpp Normal file
View File

@ -0,0 +1,67 @@
#include <QStringList>
#include "csv.h"
/*
RFC 4180 parser with the following enchancements:
- allows an arbitrary delimiter
- allows LF line ends in addition to CRLF line ends
*/
bool CSV::readEntry(QStringList &list)
{
int state = 0;
char c;
QByteArray field;
while (_device->getChar(&c)) {
switch (state) {
case 0:
if (c == '\r')
state = 3;
else if (c == '\n') {
list.append(field);
_line++;
return true;
} else if (c == _delimiter) {
list.append(field);
field.clear();
} else if (c == '"') {
if (!field.isEmpty())
return false;
state = 1;
} else
field.append(c);
break;
case 1:
if (c == '"')
state = 2;
else {
field.append(c);
if (c == '\n')
_line++;
}
break;
case 2:
if (c == '"') {
field.append('"');
state = 1;
} else if (c == _delimiter || c == '\r' || c == '\n') {
_device->ungetChar(c);
state = 0;
} else
return false;
break;
case 3:
if (c == '\n') {
_device->ungetChar(c);
state = 0;
} else
return false;
break;
}
}
list.append(field);
return (state == 0);
}

22
src/data/csv.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef CSV_H
#define CSV_H
#include <QIODevice>
class CSV
{
public:
CSV(QIODevice *device, char delimiter = ',')
: _device(device), _delimiter(delimiter), _line(1) {}
bool readEntry(QStringList &list);
bool atEnd() const {return _device->atEnd();}
int line() const {return _line;}
private:
QIODevice *_device;
char _delimiter;
int _line;
};
#endif // CSV_H

View File

@ -1,3 +1,5 @@
#include <QStringList>
#include "csv.h"
#include "csvparser.h"
bool CSVParser::parse(QFile *file, QList<TrackData> &tracks,
@ -7,42 +9,38 @@ bool CSVParser::parse(QFile *file, QList<TrackData> &tracks,
Q_UNUSED(tracks);
Q_UNUSED(routes);
Q_UNUSED(polygons);
bool res;
CSV csv(file);
QStringList entry;
bool ok;
_errorLine = 1;
_errorString.clear();
while (!file->atEnd()) {
QByteArray line = file->readLine();
QList<QByteArray> list = line.split(',');
if (list.size() < 3) {
while (!csv.atEnd()) {
if (!csv.readEntry(entry) || entry.size() < 3) {
_errorString = "Parse error";
_errorLine = csv.line();
return false;
}
qreal lon = list[0].trimmed().toDouble(&res);
if (!res || (lon < -180.0 || lon > 180.0)) {
double lon = entry.at(0).trimmed().toDouble(&ok);
if (!ok || (lon < -180.0 || lon > 180.0)) {
_errorString = "Invalid longitude";
_errorLine = csv.line();
return false;
}
qreal lat = list[1].trimmed().toDouble(&res);
if (!res || (lat < -90.0 || lat > 90.0)) {
double lat = entry.at(1).trimmed().toDouble(&ok);
if (!ok || (lat < -90.0 || lat > 90.0)) {
_errorString = "Invalid latitude";
_errorLine = csv.line();
return false;
}
Waypoint wp(Coordinates(lon, lat));
QByteArray ba = list[2].trimmed();
QString name = QString::fromUtf8(ba.data(), ba.size());
wp.setName(name);
if (list.size() > 3) {
ba = list[3].trimmed();
wp.setDescription(QString::fromUtf8(ba.data(), ba.size()));
}
wp.setName(entry.at(2).trimmed());
if (entry.size() > 3)
wp.setDescription(entry.at(3).trimmed());
waypoints.append(wp);
_errorLine++;
entry.clear();
}
return true;

167
src/data/cupparser.cpp Normal file
View File

@ -0,0 +1,167 @@
#include <cmath>
#include <QStringList>
#include "csv.h"
#include "cupparser.h"
enum SegmentType {
Header, Waypoints, Tasks
};
static double latitude(const QString &str)
{
bool ok;
if (str.length() != 9)
return NAN;
int deg = str.left(2).toInt(&ok);
if (!ok || deg > 90)
return NAN;
double min = str.mid(2, 6).toDouble(&ok);
if (!ok || min > 60)
return NAN;
double dd = deg + min/60.0;
return (str.right(1) == "S") ? -dd : dd;
}
static double longitude(const QString &str)
{
bool ok;
if (str.length() != 10)
return NAN;
int deg = str.left(3).toInt(&ok);
if (!ok || deg > 180)
return NAN;
double min = str.mid(3, 6).toDouble(&ok);
if (!ok || min > 60)
return NAN;
double dd = deg + min/60.0;
return (str.right(1) == "W") ? -dd : dd;
}
static double elevation(const QString &str)
{
bool ok;
double ele;
if (str.right(2) == "ft")
ele = str.left(str.length() - 2).toDouble(&ok) * 0.3048;
else if (str.right(1) == "m")
ele = str.left(str.length() - 1).toDouble(&ok);
else
return NAN;
return ok ? ele : NAN;
}
bool CUPParser::waypoint(const QStringList &entry, QVector<Waypoint> &waypoints)
{
if (entry.size() < 11) {
_errorString = "Invalid number of fields";
return false;
}
double lon = longitude(entry.at(4));
if (std::isnan(lon)) {
_errorString = "Invalid longitude";
return false;
}
double lat = latitude(entry.at(3));
if (std::isnan(lat)) {
_errorString = "Invalid latitude";
return false;
}
Waypoint wp(Coordinates(lon, lat));
wp.setName(entry.at(0));
wp.setDescription(entry.at(10));
wp.setElevation(elevation(entry.at(5)));
waypoints.append(wp);
return true;
}
bool CUPParser::task(const QStringList &entry,
const QVector<Waypoint> &waypoints, QList<RouteData> &routes)
{
if (entry.size() < 3) {
_errorString = "Invalid number of fields";
return false;
}
RouteData r;
r.setName(entry.at(0));
for (int i = 1; i < entry.size(); i++) {
if (entry.at(i) == "???")
continue;
Waypoint w;
for (int j = 0; j < waypoints.size(); j++) {
if (waypoints.at(j).name() == entry.at(i)) {
w = waypoints.at(j);
break;
}
}
if (w.coordinates().isNull()) {
_errorString = entry.at(i) + ": unknown turnpoint";
return false;
}
r.append(w);
}
routes.append(r);
return true;
}
bool CUPParser::parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QList<Area> &polygons,
QVector<Waypoint> &waypoints)
{
Q_UNUSED(tracks);
Q_UNUSED(polygons);
CSV csv(file);
QStringList entry;
SegmentType segment = Header;
while (!csv.atEnd()) {
if (!csv.readEntry(entry)) {
_errorString = "CSV parse error";
_errorLine = csv.line();
return false;
}
if (segment == Header) {
segment = Waypoints;
if (entry.size() >= 11 && entry.at(3) == "lat"
&& entry.at(4) == "lon") {
entry.clear();
continue;
}
} else if (segment == Waypoints && entry.size() == 1
&& entry.at(0) == "-----Related Tasks-----") {
segment = Tasks;
entry.clear();
continue;
}
if (segment == Waypoints) {
if (!waypoint(entry, waypoints))
return false;
} else if (segment == Tasks) {
if (entry.at(0) != "Options" && !entry.at(0).startsWith("ObsZone=")
&& !task(entry, waypoints, routes))
return false;
}
entry.clear();
_errorLine = csv.line();
}
return true;
}

25
src/data/cupparser.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef CUPPARSER_H
#define CUPPARSER_H
#include "parser.h"
class CUPParser : public Parser
{
public:
CUPParser() : _errorLine(0) {}
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:
bool waypoint(const QStringList &entry, QVector<Waypoint> &waypoints);
bool task(const QStringList &entry, const QVector<Waypoint> &waypoints,
QList<RouteData> &routes);
QString _errorString;
int _errorLine;
};
#endif // CUPPARSER_H

View File

@ -17,6 +17,7 @@
#include "geojsonparser.h"
#endif // ENABLE_GEOJSON
#include "exifparser.h"
#include "cupparser.h"
#include "dem.h"
#include "data.h"
@ -37,6 +38,7 @@ static SLFParser slf;
static GeoJSONParser geojson;
#endif // ENABLE_GEOJSON
static EXIFParser exif;
static CUPParser cup;
static QHash<QString, Parser*> parsers()
{
@ -60,6 +62,7 @@ static QHash<QString, Parser*> parsers()
#endif // ENABLE_GEOJSON
hash.insert("jpeg", &exif);
hash.insert("jpg", &exif);
hash.insert("cup", &cup);
return hash;
}
@ -68,13 +71,35 @@ static QHash<QString, Parser*> parsers()
QHash<QString, Parser*> Data::_parsers = parsers();
bool Data::_useDEM = false;
void Data::processData(const QList<TrackData> &trackData,
const QList<RouteData> &routeData)
void Data::processData(QList<TrackData> &trackData, QList<RouteData> &routeData)
{
for (int i = 0; i < trackData.count(); i++)
for (int i = 0; i < trackData.count(); i++) {
TrackData &track = trackData[i];
for (int j = 0; j < track.size(); j++) {
SegmentData &segment = track[j];
for (int k = 0; k < segment.size(); k++) {
Trackpoint &t = segment[k];
if (!t.hasElevation() || _useDEM) {
qreal elevation = DEM::elevation(t.coordinates());
if (!std::isnan(elevation))
t.setElevation(elevation);
}
}
}
_tracks.append(Track(trackData.at(i)));
for (int i = 0; i < routeData.count(); i++)
}
for (int i = 0; i < routeData.count(); i++) {
RouteData &route = routeData[i];
for (int j = 0; j < route.size(); j++) {
Waypoint &w = route[j];
if (!w.hasElevation() || _useDEM) {
qreal elevation = DEM::elevation(w.coordinates());
if (!std::isnan(elevation))
w.setElevation(elevation);
}
}
_routes.append(Route(routeData.at(i)));
}
for (int i = 0; i < _waypoints.size(); i++) {
if (!_waypoints.at(i).hasElevation() || _useDEM) {
qreal elevation = DEM::elevation(_waypoints.at(i).coordinates());
@ -147,6 +172,7 @@ QString Data::formats()
return
qApp->translate("Data", "Supported files") + " (" + supported + ");;"
+ qApp->translate("Data", "CSV files") + " (*.csv);;"
+ qApp->translate("Data", "CUP files") + " (*.cup);;"
+ qApp->translate("Data", "FIT files") + " (*.fit);;"
#ifdef ENABLE_GEOJSON
+ qApp->translate("Data", "GeoJSON files") + " (*.geojson *.json);;"
@ -177,6 +203,4 @@ QStringList Data::filter()
void Data::useDEM(bool use)
{
_useDEM = use;
Route::useDEM(use);
Track::useDEM(use);
}

View File

@ -31,8 +31,7 @@ public:
static void useDEM(bool use);
private:
void processData(const QList<TrackData> &trackData,
const QList<RouteData> &routeData);
void processData(QList<TrackData> &trackData, QList<RouteData> &routeData);
bool _valid;
QString _errorString;

View File

@ -113,9 +113,12 @@ Coordinates EXIFParser::coordinates(TIFFFile &file, const IFDEntry &lon,
if (!c.isValid())
return Coordinates();
if (lonRef.offset == 'W')
char ew = file.isBE() ? lonRef.offset >> 24 : lonRef.offset;
char ns = file.isBE() ? latRef.offset >> 24 : latRef.offset;
if (ew == 'W')
c.rlon() = -c.lon();
if (latRef.offset == 'S')
if (ns == 'S')
c.rlat() = -c.lat();
return c;

View File

@ -87,13 +87,10 @@ template<class T> bool FITParser::readValue(CTX &ctx, T &val)
ctx.len -= sizeof(T);
if (sizeof(T) > 1) {
if (ctx.endian)
val = qFromBigEndian(data);
else
val = qFromLittleEndian(data);
} else
val = data;
if (ctx.endian)
val = qFromBigEndian(data);
else
val = qFromLittleEndian(data);
return true;
}
@ -268,6 +265,14 @@ bool FITParser::parseData(CTX &ctx, const MessageDefinition *def)
if (val != 0x7f)
ctx.trackpoint.setTemperature((qint8)val);
break;
case 73:
if (val != 0xffffffff)
ctx.trackpoint.setSpeed(val / 1000.0f);
break;
case 78:
if (val != 0xffffffff)
ctx.trackpoint.setElevation((val / 5.0) - 500);
break;
default:
break;

View File

@ -54,6 +54,7 @@ public:
return false;
return true;
}
bool hasTime() const
{
for (int i = 0; i < size(); i++) {

View File

@ -130,6 +130,8 @@ bool IGCParser::readBRecord(SegmentData &segment, const char *line,
if (len < 35)
return false;
if (line[24] != 'A')
return true;
if (!readTimestamp(line + 1, time)) {
_errorString = "Invalid timestamp";

View File

@ -1,9 +1,6 @@
#include "dem.h"
#include "route.h"
bool Route::_useDEM = false;
Route::Route(const RouteData &data) : _data(data)
{
qreal dist = 0;
@ -34,19 +31,9 @@ Graph Route::elevation() const
graph.append(GraphSegment());
GraphSegment &gs = graph.last();
for (int i = 0; i < _data.size(); i++) {
if (_data.at(i).hasElevation() && !_useDEM)
gs.append(GraphPoint(_distance.at(i), NAN,
_data.at(i).elevation()));
else {
qreal elevation = DEM::elevation(_data.at(i).coordinates());
if (!std::isnan(elevation))
gs.append(GraphPoint(_distance.at(i), NAN, elevation));
else if (_data.at(i).hasElevation())
gs.append(GraphPoint(_distance.at(i), NAN,
_data.at(i).elevation()));
}
}
for (int i = 0; i < _data.size(); i++)
if (_data.at(i).hasElevation())
gs.append(GraphPoint(_distance.at(i), NAN, _data.at(i).elevation()));
return graph;
}

View File

@ -13,7 +13,7 @@ public:
Path path() const;
const QVector<Waypoint> &waypoints() const {return _data;}
const RouteData &data() const {return _data;}
Graph elevation() const;
@ -24,13 +24,9 @@ public:
bool isValid() const {return _data.size() >= 2;}
static void useDEM(bool use) {_useDEM = use;}
private:
RouteData _data;
QVector<qreal> _distance;
static bool _useDEM;
};
#endif // ROUTE_H

View File

@ -1,4 +1,3 @@
#include "dem.h"
#include "track.h"
@ -13,7 +12,6 @@ int Track::_pauseInterval = 10;
bool Track::_outlierEliminate = true;
bool Track::_useReportedSpeed = false;
bool Track::_useDEM = false;
static qreal median(QVector<qreal> &v)
@ -178,21 +176,10 @@ Graph Track::elevation() const
GraphSegment gs;
for (int j = 0; j < sd.size(); j++) {
if (seg.outliers.contains(j))
if (!sd.at(j).hasElevation() || seg.outliers.contains(j))
continue;
if (sd.at(j).hasElevation() && !_useDEM)
gs.append(GraphPoint(seg.distance.at(j), seg.time.at(j),
sd.at(j).elevation()));
else {
qreal elevation = DEM::elevation(sd.at(j).coordinates());
if (!std::isnan(elevation))
gs.append(GraphPoint(seg.distance.at(j), seg.time.at(j),
elevation));
else if (sd.at(j).hasElevation())
gs.append(GraphPoint(seg.distance.at(j), seg.time.at(j),
sd.at(j).elevation()));
}
gs.append(GraphPoint(seg.distance.at(j), seg.time.at(j),
sd.at(j).elevation()));
}
ret.append(filter(gs, _elevationWindow));

View File

@ -45,7 +45,6 @@ public:
static void setOutlierElimination(bool eliminate)
{_outlierEliminate = eliminate;}
static void useReportedSpeed(bool use) {_useReportedSpeed = use;}
static void useDEM(bool use) {_useDEM = use;}
private:
struct Segment {
@ -71,7 +70,6 @@ private:
static qreal _pauseSpeed;
static int _pauseInterval;
static bool _useReportedSpeed;
static bool _useDEM;
};
#endif // TRACK_H

View File

@ -9,7 +9,7 @@
#define CHECK(condition) \
if (!(condition)) { \
_errorString = "Invalid/corrupted IMG file"; \
_errorString = "Unsupported or invalid IMG file"; \
return; \
}
@ -85,13 +85,8 @@ IMG::IMG(const QString &fileName)
&& read(type, sizeof(type)) && readValue(size) && readValue(part));
SubFile::Type tt = SubFile::type(type);
if (tt == SubFile::GMP) {
_errorString = "NT maps not supported";
return;
}
QString fn(QByteArray(name, sizeof(name)));
if (VectorTile::isTileFile(tt)) {
if (SubFile::isTileFile(tt)) {
VectorTile *tile;
QMap<QString, VectorTile*>::iterator it = tileMap.find(fn);
if (it == tileMap.end()) {
@ -101,7 +96,7 @@ IMG::IMG(const QString &fileName)
tile = *it;
SubFile *file = part ? tile->file(tt)
: tile->addFile(this, tt, size);
: tile->addFile(this, tt);
CHECK(file);
_file.seek(offset + 0x20);
@ -114,7 +109,7 @@ IMG::IMG(const QString &fileName)
} else if (tt == SubFile::TYP) {
SubFile *typ = 0;
if (typFile.isNull()) {
_typ = new SubFile(this, size);
_typ = new SubFile(this);
typ = _typ;
typFile = fn;
} else if (fn == typFile)
@ -166,7 +161,7 @@ void IMG::load()
{
Q_ASSERT(!_style);
if (_typ && _typ->isValid())
if (_typ)
_style = new Style(_typ);
else {
QFile typFile(ProgramPaths::typFile());
@ -227,10 +222,7 @@ template<class T> bool IMG::readValue(T &val)
if (read((char*)&data, sizeof(T)) < (qint64)sizeof(T))
return false;
if (sizeof(T) > 1)
val = qFromLittleEndian(data);
else
val = data;
val = qFromLittleEndian(data);
return true;
}

View File

@ -4,6 +4,9 @@
#include <QString>
#include <QDebug>
#define FIRST_SHIELD Label::Shield::USInterstate
#define LAST_SHIELD Label::Shield::Oval
class Label {
public:
class Shield

View File

@ -35,7 +35,8 @@ static QString capitalize(const QString &str)
if (str.isEmpty())
return str;
for (int i = 0; i < str.size(); i++)
if (str.at(i).isLetter() && !str.at(i).isUpper())
if (str.at(i).isLetter() && !(str.at(i).isUpper()
|| str.at(i) == QChar(0x00DF)))
return str;
QString ret(str);
@ -53,15 +54,18 @@ bool LBLFile::init()
{
Handle hdl;
quint16 codepage;
quint8 multiplier, poiMultiplier;
if (!(seek(hdl, 0x15) && readUInt32(hdl, _offset)
&& readUInt32(hdl, _size) && readByte(hdl, _multiplier)
&& readByte(hdl, _encoding) && seek(hdl, 0x57)
if (!(seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _offset)
&& readUInt32(hdl, _size) && readByte(hdl, multiplier)
&& readByte(hdl, _encoding) && seek(hdl, _gmpOffset + 0x57)
&& readUInt32(hdl, _poiOffset) && readUInt32(hdl, _poiSize)
&& seek(hdl, 0xAA) && readUInt16(hdl, codepage)))
&& readByte(hdl, poiMultiplier) && seek(hdl, _gmpOffset + 0xAA)
&& readUInt16(hdl, codepage)))
return false;
_multiplier = 1<<_multiplier;
_multiplier = 1<<multiplier;
_poiMultiplier = 1<<poiMultiplier;
if (codepage == 65001)
_codec = QTextCodec::codecForName("UTF-8");
@ -102,7 +106,8 @@ Label LBLFile::label6b(Handle &hdl, quint32 offset) const
else if (c[cpt] == 0x1b)
curCharSet = Special;
else if (c[cpt] >= 0x2a && c[cpt] <= 0x2f) {
shieldType = (Label::Shield::Type)(c[cpt] - 0x29);
shieldType = static_cast<Label::Shield::Type>
(c[cpt] - 0x29);
bap = &shieldLabel;
} else if (bap == &shieldLabel
&& NORMAL_CHARS[c[cpt]] == ' ')
@ -145,7 +150,7 @@ Label LBLFile::label8b(Handle &hdl, quint32 offset) const
else
bap->append(' ');
} else if (c <= 0x07) {
shieldType = (Label::Shield::Type)c;
shieldType = static_cast<Label::Shield::Type>(c);
bap = &shieldLabel;
} else if (bap == &shieldLabel && QChar(c).isSpace()) {
bap = &label;
@ -160,14 +165,15 @@ Label LBLFile::label8b(Handle &hdl, quint32 offset) const
Label LBLFile::label(Handle &hdl, quint32 offset, bool poi)
{
if (!_size && !init())
if (!_multiplier && !init())
return QString();
quint32 labelOffset;
if (poi) {
quint32 poiOffset;
if (!(seek(hdl, _poiOffset + offset) && readUInt24(hdl, poiOffset)
&& (poiOffset & 0x3FFFFF)))
if (!(_poiSize >= offset * _poiMultiplier
&& seek(hdl, _poiOffset + offset * _poiMultiplier)
&& readUInt24(hdl, poiOffset) && (poiOffset & 0x3FFFFF)))
return QString();
labelOffset = _offset + (poiOffset & 0x3FFFFF) * _multiplier;
} else

View File

@ -9,9 +9,12 @@ class QTextCodec;
class LBLFile : public SubFile
{
public:
LBLFile(IMG *img, quint32 size)
: SubFile(img, size), _offset(0), _size(0), _poiOffset(0), _poiSize(0),
_multiplier(0), _encoding(0), _codec(0) {}
LBLFile(IMG *img)
: SubFile(img), _codec(0), _offset(0), _size(0), _poiOffset(0),
_poiSize(0), _poiMultiplier(0), _multiplier(0), _encoding(0) {}
LBLFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset),
_codec(0), _offset(0), _size(0), _poiOffset(0), _poiSize(0),
_poiMultiplier(0), _multiplier(0), _encoding(0) {}
Label label(Handle &hdl, quint32 offset, bool poi = false);
@ -21,13 +24,14 @@ private:
Label label6b(Handle &hdl, quint32 offset) const;
Label label8b(Handle &hdl, quint32 offset) const;
QTextCodec *_codec;
quint32 _offset;
quint32 _size;
quint32 _poiOffset;
quint32 _poiSize;
quint8 _poiMultiplier;
quint8 _multiplier;
quint8 _encoding;
QTextCodec *_codec;
};
#endif // LBLFILE_H

View File

@ -3,22 +3,21 @@
bool NETFile::init()
{
Handle hdl;
quint8 multiplier;
if (!(seek(hdl, 0x15) && readUInt32(hdl, _offset)
&& readUInt32(hdl, _size) && readByte(hdl, _multiplier)))
if (!(seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _offset)
&& readUInt32(hdl, _size) && readByte(hdl, multiplier)))
return false;
_multiplier = 1<<_multiplier;
_multiplier = 1<<multiplier;
return true;
}
bool NETFile::lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset)
{
if (!_init) {
if (!(_init = init()))
return false;
}
if (!_multiplier && !init())
return false;
if (!(seek(hdl, _offset + netOffset * _multiplier)
&& readUInt24(hdl, lblOffset)))

View File

@ -6,7 +6,9 @@
class NETFile : public SubFile
{
public:
NETFile(IMG *img, quint32 size) : SubFile(img, size), _init(false) {}
NETFile(IMG *img) : SubFile(img), _offset(0), _size(0), _multiplier(0) {}
NETFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset),
_offset(0), _size(0), _multiplier(0) {}
bool lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset);
@ -16,8 +18,6 @@ private:
quint32 _offset;
quint32 _size;
quint8 _multiplier;
bool _init;
};
#endif // NETFILE_H

View File

@ -1,10 +1,26 @@
#include "trefile.h"
#include "common/rectc.h"
#include "units.h"
#include "lblfile.h"
#include "netfile.h"
#include "rgnfile.h"
static int bitSize(quint8 baseSize, bool variableSign, bool extraBit)
{
int bits = 2;
if (baseSize <= 9)
bits += baseSize;
else
bits += 2 * baseSize - 9;
if (variableSign)
bits++;
if (extraBit)
bits++;
return bits;
}
bool RGNFile::BitStream::read(int bits, quint32 &val)
{
val = 0;
@ -34,29 +50,42 @@ bool RGNFile::BitStream::read(int bits, quint32 &val)
return true;
}
bool RGNFile::BitStream::readDelta(int bits, int sign, bool extraBit,
RGNFile::DeltaStream::DeltaStream(const SubFile &file, Handle &hdl,
quint32 length, quint8 info, bool extraBit, bool extended)
: BitStream(file, hdl, length), _readBits(0xFFFFFFFF)
{
_extraBit = extraBit ? 1 : 0;
if (!(sign(_lonSign) && sign(_latSign)))
return;
if (extended) {
quint32 b;
if (!read(1, b))
return;
}
_lonBits = bitSize(info & 0x0F, !_lonSign, extraBit);
_latBits = bitSize(info >> 4, !_latSign, false);
_readBits = _lonBits + _latBits;
}
bool RGNFile::DeltaStream::readDelta(int bits, int sign, int extraBit,
qint32 &delta)
{
quint32 value;
int bo = 0;
if (!read(bits, value))
return false;
if (extraBit) {
value>>=1;
bo = 1;
}
value >>= extraBit;
if (!sign) {
qint32 signMask = 1 << (bits - bo - 1);
qint32 signMask = 1 << (bits - extraBit - 1);
if (value & signMask) {
qint32 comp = value ^ signMask;
if (comp)
delta = comp - signMask;
else {
qint32 other;
if (!readDelta(bits - bo, sign, false, other))
if (!readDelta(bits - extraBit, sign, false, other))
return false;
if (other < 0)
delta = 1 - signMask + other;
@ -73,42 +102,15 @@ bool RGNFile::BitStream::readDelta(int bits, int sign, bool extraBit,
return true;
}
bool RGNFile::BitStream::finish()
{
while (_length--)
if (!_file.readByte(_hdl, _data))
return false;
return true;
}
bool RGNFile::init()
{
Handle hdl;
if (!(seek(hdl, 0x15) && readUInt32(hdl, _offset)
&& readUInt32(hdl, _size) && readUInt32(hdl, _polygonsOffset)
&& readUInt32(hdl, _polygonsSize) && seek(hdl, 0x39)
&& readUInt32(hdl, _linesOffset) && readUInt32(hdl, _linesSize)
&& seek(hdl, 0x55) && readUInt32(hdl, _pointsOffset)
&& readUInt32(hdl, _pointsSize)))
return false;
if (_offset + _size > size())
return false;
return true;
}
bool RGNFile::sign(BitStream &bs, int &val)
bool RGNFile::DeltaStream::sign(int &val)
{
quint32 bit;
val = 0;
if (!bs.read(1, bit))
if (!read(1, bit))
return false;
if (bit) {
if (!bs.read(1, bit))
if (!read(1, bit))
return false;
val = bit ? -1 : 1;
}
@ -116,20 +118,41 @@ bool RGNFile::sign(BitStream &bs, int &val)
return true;
}
int RGNFile::bitSize(quint8 baseSize, bool variableSign, bool extraBit)
bool RGNFile::init()
{
int bits = 2;
if (baseSize <= 9)
bits += baseSize;
else
bits += 2 * baseSize - 9;
Handle hdl;
quint16 hdrLen;
if (variableSign)
bits++;
if (extraBit)
bits++;
if (!(seek(hdl, _gmpOffset) && readUInt16(hdl, hdrLen)
&& seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _offset)
&& readUInt32(hdl, _size)))
return false;
return bits;
if (hdrLen >= 0x5D) {
if (!(readUInt32(hdl, _polygonsOffset) && readUInt32(hdl, _polygonsSize)
&& seek(hdl, _gmpOffset + 0x39) && readUInt32(hdl, _linesOffset)
&& readUInt32(hdl, _linesSize) && seek(hdl, _gmpOffset + 0x55)
&& readUInt32(hdl, _pointsOffset) && readUInt32(hdl, _pointsSize)))
return false;
}
if (hdrLen >= 0x7D) {
quint32 dictOffset, dictSize;
if (!(seek(hdl, _gmpOffset + 0x71) && readUInt32(hdl, dictOffset)
&& readUInt32(hdl, dictSize)))
return false;
// NT maps
if (dictSize || dictOffset) {
qWarning("NT compression not supported");
return false;
}
}
_init = true;
return true;
}
bool RGNFile::polyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
@ -167,28 +190,17 @@ bool RGNFile::polyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
poly.type = (segment.type() == Segment::Polygon)
? ((quint32)(type & 0x7F)) << 8 : ((quint32)(type & 0x3F)) << 8;
RectC br;
QPoint pos(subdiv->lon() + ((qint32)lon<<(24-subdiv->bits())),
subdiv->lat() + ((qint32)lat<<(24-subdiv->bits())));
Coordinates c(toWGS84(pos.x()), toWGS84(pos.y()));
br = br.united(c);
RectC br(c, c);
poly.points.append(QPointF(c.lon(), c.lat()));
BitStream bs(*this, hdl, len);
int lonSign, latSign;
if (!sign(bs, lonSign) || !sign(bs, latSign))
return false;
bool extraBit = labelPtr & 0x400000;
int lonBits = bitSize(bitstreamInfo & 0x0F, !lonSign, extraBit);
int latBits = bitSize(bitstreamInfo >> 4, !latSign, false);
while (bs.hasNext(lonBits + latBits)) {
qint32 lonDelta, latDelta;
if (!(bs.readDelta(lonBits, lonSign, extraBit, lonDelta)
&& bs.readDelta(latBits, latSign, false, latDelta)))
return false;
qint32 lonDelta, latDelta;
DeltaStream stream(*this, hdl, len, bitstreamInfo, labelPtr & 0x400000,
false);
while (stream.readNext(lonDelta, latDelta)) {
pos.rx() += lonDelta<<(24-subdiv->bits());
pos.ry() += latDelta<<(24-subdiv->bits());
@ -196,7 +208,7 @@ bool RGNFile::polyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
poly.points.append(QPointF(c.lon(), c.lat()));
br = br.united(c);
}
if (!bs.finish())
if (!(stream.atEnd() && stream.flush()))
return false;
if (!rect.intersects(br))
@ -222,10 +234,9 @@ bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl,
const SubDiv *subdiv, const Segment &segment, LBLFile *lbl, Handle &lblHdl,
QList<IMG::Poly> *polys) const
{
quint32 labelPtr;
quint8 type, subtype, len8, len82, bitstreamInfo;
quint32 len, labelPtr = 0;
quint8 type, subtype, bitstreamInfo;
qint16 lon, lat;
quint16 len;
if (!seek(hdl, segment.start()))
@ -235,7 +246,8 @@ bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl,
IMG::Poly poly;
if (!(readByte(hdl, type) && readByte(hdl, subtype)
&& readInt16(hdl, lon) && readInt16(hdl, lat) && readByte(hdl, len8)))
&& readInt16(hdl, lon) && readInt16(hdl, lat)
&& readVUInt32(hdl, len) && readByte(hdl, bitstreamInfo)))
return false;
if (subtype & 0x80) {
@ -243,40 +255,17 @@ bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl,
return false;
}
if (len8 & 0x01)
len = (len8>>1) - 1;
else {
if (!readByte(hdl, len82))
return false;
len = ((len8 | ((quint16)len82<<8))>>2) - 1;
}
if (!readByte(hdl, bitstreamInfo))
return false;
poly.type = 0x10000 + (quint16(type) << 8) + (subtype & 0x1F);
RectC br;
QPoint pos(subdiv->lon() + ((qint32)lon<<(24-subdiv->bits())),
subdiv->lat() + ((qint32)lat<<(24-subdiv->bits())));
Coordinates c(toWGS84(pos.x()), toWGS84(pos.y()));
br = br.united(c);
RectC br(c, c);
poly.points.append(QPointF(c.lon(), c.lat()));
BitStream bs(*this, hdl, len);
int lonSign, latSign;
if (!sign(bs, lonSign) || !sign(bs, latSign))
return false;
quint32 extraBit;
bs.read(1, extraBit);
int lonBits = bitSize(bitstreamInfo & 0x0F, !lonSign, extraBit);
int latBits = bitSize(bitstreamInfo >> 4, !latSign, extraBit);
while (bs.hasNext(lonBits + latBits)) {
qint32 lonDelta, latDelta;
if (!(bs.readDelta(lonBits, lonSign, false, lonDelta)
&& bs.readDelta(latBits, latSign, false, latDelta)))
return false;
qint32 lonDelta, latDelta;
DeltaStream stream(*this, hdl, len - 1, bitstreamInfo, false, true);
while (stream.readNext(lonDelta, latDelta)) {
pos.rx() += lonDelta<<(24-subdiv->bits());
pos.ry() += latDelta<<(24-subdiv->bits());
@ -284,19 +273,21 @@ bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl,
poly.points.append(QPointF(c.lon(), c.lat()));
br = br.united(c);
}
if (!bs.finish())
if (!(stream.atEnd() && stream.flush()))
return false;
if (subtype & 0x20) {
if ((subtype & 0x20)) {
if (!readUInt24(hdl, labelPtr))
return false;
if (lbl && (labelPtr & 0x3FFFFF))
poly.label = lbl->label(lblHdl, labelPtr & 0x3FFFFF);
}
} else
labelPtr = 0;
if (!rect.intersects(br))
continue;
if (lbl && (labelPtr & 0x3FFFFF))
poly.label = lbl->label(lblHdl, labelPtr & 0x3FFFFF);
polys->append(poly);
}
@ -404,7 +395,7 @@ void RGNFile::objects(const RectC &rect, const SubDiv *subdiv, LBLFile *lbl,
{
Handle rgnHdl, lblHdl, netHdl;
if (!_size && !init())
if (!_init && !init())
return;
QVector<RGNFile::Segment> seg(segments(rgnHdl, subdiv));
@ -436,7 +427,7 @@ void RGNFile::extObjects(const RectC &rect, const SubDiv *subdiv, LBLFile *lbl,
{
Handle rgnHdl, lblHdl;
if (!_size && !init())
if (!_init && !init())
return;
if (polygons && subdiv->polygonsOffset() != subdiv->polygonsEnd()) {
@ -459,7 +450,7 @@ void RGNFile::extObjects(const RectC &rect, const SubDiv *subdiv, LBLFile *lbl,
quint32 start = _pointsOffset + subdiv->pointsOffset();
quint32 end = subdiv->pointsEnd()
? _pointsOffset + subdiv->pointsEnd()
: _pointsOffset + _linesSize;
: _pointsOffset + _pointsSize;
extPointObjects(rect, rgnHdl, subdiv, Segment(start, end,
Segment::Point), lbl, lblHdl, points);
}

View File

@ -11,10 +11,13 @@ class NETFile;
class RGNFile : public SubFile
{
public:
RGNFile(IMG *img, quint32 size)
: SubFile(img, size), _offset(0), _size(0), _polygonsOffset(0),
_polygonsSize(), _linesOffset(), _linesSize(), _pointsOffset(),
_pointsSize() {}
RGNFile(IMG *img)
: SubFile(img), _offset(0), _size(0), _polygonsOffset(0),
_polygonsSize(0), _linesOffset(0), _linesSize(0), _pointsOffset(0),
_pointsSize(0), _init(false) {}
RGNFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset), _offset(0),
_size(0), _polygonsOffset(0), _polygonsSize(0), _linesOffset(0),
_linesSize(0), _pointsOffset(0), _pointsSize(0), _init(false) {}
void objects(const RectC &rect, const SubDiv *subdiv, LBLFile *lbl,
NETFile *net, QList<IMG::Poly> *polygons, QList<IMG::Poly> *lines,
@ -53,27 +56,45 @@ private:
class BitStream {
public:
BitStream(const SubFile &file, Handle &hdl, quint16 length)
BitStream(const SubFile &file, Handle &hdl, quint32 length)
: _file(file), _hdl(hdl), _length(length), _remaining(0) {}
bool read(int bits, quint32 &val);
bool readDelta(int bits, int sign, bool extraBit, qint32 &delta);
bool hasNext(int bits) const
{return _length * 8 + _remaining >= (quint32)bits;}
bool finish();
bool flush() {return _file.seek(_hdl, _hdl.pos + _length);}
quint32 bitsAvailable() const {return _length * 8 + _remaining;}
private:
const SubFile &_file;
Handle &_hdl;
quint16 _length;
quint32 _remaining;
quint32 _length, _remaining;
quint8 _data;
};
static bool sign(BitStream &bs, int &val);
static int bitSize(quint8 baseSize, bool variableSign, bool extraBit);
class DeltaStream : public BitStream {
public:
DeltaStream(const SubFile &file, Handle &hdl, quint32 length,
quint8 info, bool extraBit, bool extended);
bool readNext(qint32 &lonDelta, qint32 &latDelta)
{
return hasNext()
? (readDelta(_lonBits, _lonSign, _extraBit, lonDelta)
&& readDelta(_latBits, _latSign, false, latDelta))
: false;
}
bool atEnd() const {return (_readBits != 0xFFFFFFFF && !hasNext());}
private:
bool hasNext() const {return bitsAvailable() >= _readBits;}
bool sign(int &val);
bool readDelta(int bits, int sign, int extraBit, qint32 &delta);
int _lonSign, _latSign, _extraBit;
quint32 _lonBits, _latBits, _readBits;
};
bool init();
QVector<Segment> segments(Handle &hdl, const SubDiv *subdiv) const;
bool polyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
const Segment &segment, LBLFile *lbl, Handle &lblHdl, NETFile *net,
@ -99,6 +120,8 @@ private:
quint32 _linesSize;
quint32 _pointsOffset;
quint32 _pointsSize;
bool _init;
};
#ifndef QT_NO_DEBUG

View File

@ -942,7 +942,7 @@ Style::Style(SubFile *typ)
defaultPolygonStyle();
defaultPointStyle();
if (typ && typ->isValid())
if (typ)
parseTYPFile(typ);
}

View File

@ -20,21 +20,13 @@ SubFile::Type SubFile::type(const char str[3])
return Unknown;
}
SubFile::SubFile(QFile *file) : _img(0), _file(file), _size(0)
SubFile::SubFile(QFile *file) :_gmpOffset(0), _img(0), _file(file), _blocks(0)
{
if (!_file->open(QIODevice::ReadOnly))
qWarning("Error opening %s: %s", qPrintable(_file->fileName()),
qPrintable(_file->errorString()));
}
bool SubFile::isValid() const
{
return _file
? _file->isOpen()
: ((quint32)_img->blockSize() * (quint32)_blocks.size() - _size
< (quint32)_img->blockSize());
}
bool SubFile::seek(Handle &handle, quint32 pos) const
{
Q_ASSERT(_img || _file);
@ -46,9 +38,9 @@ bool SubFile::seek(Handle &handle, quint32 pos) const
int blockNum = pos / blockSize;
if (handle.blockNum != blockNum) {
if (blockNum >= _blocks.size())
if (blockNum >= _blocks->size())
return false;
if (!_img->readBlock(_blocks.at(blockNum), handle.data))
if (!_img->readBlock(_blocks->at(blockNum), handle.data))
return false;
handle.blockNum = blockNum;
}
@ -74,29 +66,55 @@ bool SubFile::readByte(Handle &handle, quint8 &val) const
}
}
quint32 SubFile::size() const
bool SubFile::readVUInt32(Handle &hdl, quint32 &val) const
{
return _img ? _size : (quint32)_file->size();
quint8 bytes, shift, b;
if (!readByte(hdl, b))
return false;
if ((b & 1) == 0) {
if ((b & 2) == 0) {
bytes = ((b >> 2) & 1) ^ 3;
shift = 5;
} else {
shift = 6;
bytes = 1;
}
} else {
shift = 7;
bytes = 0;
}
val = b >> (8 - shift);
for (int i = 1; i <= bytes; i++) {
if (!readByte(hdl, b))
return false;
val |= (((quint32)b) << (i * 8)) >> (8 - shift);
}
return true;
}
QString SubFile::fileName() const
{
return _img ? _img->fileName() : _file->fileName();
return _file ? _file->fileName() : _img->fileName();
}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const SubFile &file)
{
bool continuous = true;
for (int i = 1; i < file._blocks.size(); i++) {
if (file._blocks.at(i) != file._blocks.at(i-1) + 1) {
for (int i = 1; i < file._blocks->size(); i++) {
if (file._blocks->at(i) != file._blocks->at(i-1) + 1) {
continuous = false;
break;
}
}
dbg.nospace() << "SubFile(" << file._size << ", " << file._blocks.size()
<< ", " << continuous << ")";
dbg.nospace() << "SubFile(" << file._blocks->size() << ", "
<< continuous << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG

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