From 81ad083b0c06ea08ea33d5b05805161f50844ba2 Mon Sep 17 00:00:00 2001 From: Daniel Stolarski Date: Sat, 12 Oct 2019 07:28:13 +0700 Subject: gis/qmapshack: Updated for version 1.13.2. Signed-off-by: Willy Sudiarto Raharjo --- gis/qmapshack/FindPROJ4.cmake | 153 - gis/qmapshack/addqmaptool.patch | 25494 ++++++++++++++++++++++++++++++++ gis/qmapshack/line_3px_horizontal.png | Bin 0 -> 188 bytes gis/qmapshack/line_3px_vertical.png | Bin 0 -> 189 bytes gis/qmapshack/qmapshack.SlackBuild | 19 +- gis/qmapshack/qmapshack.info | 6 +- gis/qmapshack/qmt_map2jnx.patch | 1199 ++ gis/qmapshack/rgb2pct.patch | 971 ++ gis/qmapshack/splash.png | Bin 0 -> 156794 bytes 9 files changed, 27680 insertions(+), 162 deletions(-) delete mode 100644 gis/qmapshack/FindPROJ4.cmake create mode 100644 gis/qmapshack/addqmaptool.patch create mode 100644 gis/qmapshack/line_3px_horizontal.png create mode 100644 gis/qmapshack/line_3px_vertical.png create mode 100644 gis/qmapshack/qmt_map2jnx.patch create mode 100644 gis/qmapshack/rgb2pct.patch create mode 100644 gis/qmapshack/splash.png diff --git a/gis/qmapshack/FindPROJ4.cmake b/gis/qmapshack/FindPROJ4.cmake deleted file mode 100644 index a8213de4e036d..0000000000000 --- a/gis/qmapshack/FindPROJ4.cmake +++ /dev/null @@ -1,153 +0,0 @@ -#.rst: -# FindPROJ4 -# -------- -# -# Find the proj includes and library. -# -# IMPORTED Targets -# ^^^^^^^^^^^^^^^^ -# -# This module defines :prop_tgt:`IMPORTED` target ``PROJ4::proj``, -# if Proj.4 has been found. -# -# Result Variables -# ^^^^^^^^^^^^^^^^ -# -# This module defines the following variables: -# -# :: -# -# PROJ4_INCLUDE_DIRS - where to find proj_api.h, etc. -# PROJ4_LIBRARIES - List of libraries when using libproj. -# PROJ4_FOUND - True if libproj found. -# -# :: -# -# PROJ4_VERSION - The version of libproj found (x.y.z) -# PROJ4_VERSION_MAJOR - The major version of libproj -# PROJ4_VERSION_MINOR - The minor version of libproj -# PROJ4_VERSION_PATCH - The patch version of libproj -# PROJ4_VERSION_TWEAK - always 0 -# PROJ4_VERSION_COUNT - The number of version components, always 3 -# -# Hints -# ^^^^^ -# -# A user may set ``PROJ4_ROOT`` to a libproj installation root to tell this -# module where to look exclusively. - -#============================================================================= -# Copyright 2016 Kai Pastor -# -# -# This file was derived from CMake 3.5's module FindZLIB.cmake -# which has the following terms: -# -# Copyright 2001-2011 Kitware, Inc. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * The names of Kitware, Inc., the Insight Consortium, or the names of -# any consortium members, or of any contributors, may not be used to -# endorse or promote products derived from this software without -# specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS'' -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#============================================================================= - -# Search PROJ4_ROOT exclusively if it is set. -if(PROJ4_ROOT) - set(_PROJ4_SEARCH PATHS ${PROJ4_ROOT} NO_DEFAULT_PATH) -else() - set(_PROJ4_SEARCH) -endif() - -find_path(PROJ4_INCLUDE_DIR NAMES proj_api.h ${_PROJ4_SEARCH} PATH_SUFFIXES include) -mark_as_advanced(PROJ4_INCLUDE_DIR) - -if(PROJ4_INCLUDE_DIR AND EXISTS "${PROJ4_INCLUDE_DIR}/proj_api.h") - file(STRINGS "${PROJ4_INCLUDE_DIR}/proj_api.h" PROJ4_H REGEX "^#define PJ_VERSION [0-9]+$") - - string(REGEX REPLACE "^.*PJ_VERSION ([0-9]).*$" "\\1" PROJ4_VERSION_MAJOR "${PROJ4_H}") - string(REGEX REPLACE "^.*PJ_VERSION [0-9]([0-9]).*$" "\\1" PROJ4_VERSION_MINOR "${PROJ4_H}") - string(REGEX REPLACE "^.*PJ_VERSION [0-9][0-9]([0-9]).*$" "\\1" PROJ4_VERSION_PATCH "${PROJ4_H}") - set(PROJ4_VERSION "${PROJ4_VERSION_MAJOR}.${PROJ4_VERSION_MINOR}.${PROJ4_VERSION_PATCH}") - set(PROJ4_VERSION_COUNT 3) -endif() - -# Allow PROJ4_LIBRARY to be set manually, as the location of the proj library -if(NOT PROJ4_LIBRARY) - set(PROJ4_NAMES proj) - set(PROJ4_NAMES_DEBUG projd) - if(WIN32 AND DEFINED PROJ4_VERSION_MAJOR AND DEFINED PROJ4_VERSION_MINOR) - list(APPEND PROJ4_NAMES proj_${PROJ4_VERSION_MAJOR}_${PROJ4_VERSION_MINOR}) - list(APPEND PROJ4_NAMES projd_${PROJ4_VERSION_MAJOR}_${PROJ4_VERSION_MINOR}) - endif() - find_library(PROJ4_LIBRARY_RELEASE NAMES ${PROJ4_NAMES} ${_PROJ4_SEARCH} PATH_SUFFIXES lib) - find_library(PROJ4_LIBRARY_DEBUG NAMES ${PROJ4_NAMES_DEBUG} ${_PROJ4_SEARCH} PATH_SUFFIXES lib) - include(SelectLibraryConfigurations) - select_library_configurations(PROJ4) -endif() - -# handle the QUIETLY and REQUIRED arguments and set PROJ4_FOUND to TRUE if -# all listed variables are TRUE -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(PROJ4 - REQUIRED_VARS - PROJ4_LIBRARY - PROJ4_INCLUDE_DIR - VERSION_VAR - PROJ4_VERSION -) - -if(PROJ4_FOUND) - set(PROJ4_INCLUDE_DIRS ${PROJ4_INCLUDE_DIR}) - - if(NOT PROJ4_LIBRARIES) - set(PROJ4_LIBRARIES ${PROJ4_LIBRARY}) - endif() - - if(NOT TARGET PROJ4::proj) - add_library(PROJ4::proj UNKNOWN IMPORTED) - set_target_properties(PROJ4::proj PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${PROJ4_INCLUDE_DIRS}") - - if(PROJ4_LIBRARY_RELEASE) - set_property(TARGET PROJ4::proj APPEND PROPERTY - IMPORTED_CONFIGURATIONS RELEASE) - set_target_properties(PROJ4::proj PROPERTIES - IMPORTED_LOCATION_RELEASE "${PROJ4_LIBRARY_RELEASE}") - endif() - - if(PROJ4_LIBRARY_DEBUG) - set_property(TARGET PROJ4::proj APPEND PROPERTY - IMPORTED_CONFIGURATIONS DEBUG) - set_target_properties(PROJ4::proj PROPERTIES - IMPORTED_LOCATION_DEBUG "${PROJ4_LIBRARY_DEBUG}") - endif() - - if(NOT PROJ4_LIBRARY_RELEASE AND NOT PROJ4_LIBRARY_DEBUG) - set_property(TARGET PROJ4::proj APPEND PROPERTY - IMPORTED_LOCATION "${PROJ4_LIBRARY}") - endif() - endif() -endif() - diff --git a/gis/qmapshack/addqmaptool.patch b/gis/qmapshack/addqmaptool.patch new file mode 100644 index 0000000000000..71553ddcc4c46 --- /dev/null +++ b/gis/qmapshack/addqmaptool.patch @@ -0,0 +1,25494 @@ +From c6e5240ec25b91d3320f265346a904b5bd906363 Mon Sep 17 00:00:00 2001 +From: Oliver Eichler +Date: Thu, 12 Sep 2019 20:29:51 +0200 +Subject: [PATCH] [QMS-3] Add QMapTool from former sub-repo + +--- + src/qmaptool/.hgtags | 1 + + src/qmaptool/CAbout.cpp | 46 + + src/qmaptool/CAbout.h | 35 + + src/qmaptool/CMainWindow.cpp | 182 ++ + src/qmaptool/CMainWindow.h | 100 + + src/qmaptool/CMakeLists.txt | 269 +++ + src/qmaptool/CSingleInstanceProxy.cpp | 102 + + src/qmaptool/CSingleInstanceProxy.h | 41 + + src/qmaptool/GeoMath.cpp | 54 + + src/qmaptool/GeoMath.h | 31 + + src/qmaptool/IAbout.ui | 164 ++ + src/qmaptool/IMainWindow.ui | 208 ++ + src/qmaptool/README.md | 7 + + src/qmaptool/canvas/CCanvas.cpp | 189 ++ + src/qmaptool/canvas/CCanvas.h | 92 + + src/qmaptool/canvas/CDrawContextPixel.cpp | 168 ++ + src/qmaptool/canvas/CDrawContextPixel.h | 91 + + src/qmaptool/canvas/CDrawContextProj.cpp | 166 ++ + src/qmaptool/canvas/CDrawContextProj.h | 89 + + src/qmaptool/canvas/IDrawContext.cpp | 300 +++ + src/qmaptool/canvas/IDrawContext.h | 164 ++ + src/qmaptool/helpers/CDraw.cpp | 239 +++ + src/qmaptool/helpers/CDraw.h | 96 + + src/qmaptool/helpers/CGdalFile.cpp | 221 +++ + src/qmaptool/helpers/CGdalFile.h | 93 + + src/qmaptool/helpers/CSettings.h | 54 + + src/qmaptool/helpers/mitab.cpp | 260 +++ + src/qmaptool/helpers/mitab.h | 46 + + src/qmaptool/items/CItemCutMap.cpp | 97 + + src/qmaptool/items/CItemCutMap.h | 52 + + src/qmaptool/items/CItemFile.cpp | 37 + + src/qmaptool/items/CItemFile.h | 38 + + src/qmaptool/items/CItemListWidget.cpp | 157 ++ + src/qmaptool/items/CItemListWidget.h | 84 + + src/qmaptool/items/CItemMap.cpp | 82 + + src/qmaptool/items/CItemMap.h | 54 + + src/qmaptool/items/CItemMapLayer.cpp | 119 ++ + src/qmaptool/items/CItemMapLayer.h | 57 + + src/qmaptool/items/CItemRefMap.cpp | 114 ++ + src/qmaptool/items/CItemRefMap.h | 56 + + src/qmaptool/items/CItemTreeWidget.cpp | 317 +++ + src/qmaptool/items/CItemTreeWidget.h | 94 + + src/qmaptool/items/IItem.cpp | 141 ++ + src/qmaptool/items/IItem.h | 97 + + src/qmaptool/items/IItemListWidget.ui | 127 ++ + src/qmaptool/items/IItemTreeWidget.ui | 135 ++ + src/qmaptool/locale/qmaptool.ts | 1675 ++++++++++++++++ + src/qmaptool/locale/qmaptool_de.ts | 1712 ++++++++++++++++ + src/qmaptool/locale/qmaptool_es.ts | 1715 +++++++++++++++++ + src/qmaptool/main.cpp | 76 + + src/qmaptool/overlay/COverlayCutMap.cpp | 644 +++++++ + src/qmaptool/overlay/COverlayCutMap.h | 105 + + src/qmaptool/overlay/COverlayGridTool.cpp | 348 ++++ + src/qmaptool/overlay/COverlayGridTool.h | 68 + + src/qmaptool/overlay/COverlayRefMap.cpp | 747 +++++++ + src/qmaptool/overlay/COverlayRefMap.h | 103 + + src/qmaptool/overlay/IOverlay.cpp | 36 + + src/qmaptool/overlay/IOverlay.h | 43 + + src/qmaptool/overlay/IOverlayCutMap.ui | 202 ++ + src/qmaptool/overlay/IOverlayGridTool.ui | 184 ++ + src/qmaptool/overlay/IOverlayRefMap.ui | 351 ++++ + src/qmaptool/overlay/gridtool/CGridPlacer.cpp | 274 +++ + src/qmaptool/overlay/gridtool/CGridPlacer.h | 85 + + src/qmaptool/overlay/gridtool/CGridPoint.cpp | 184 ++ + src/qmaptool/overlay/gridtool/CGridPoint.h | 70 + + .../overlay/gridtool/CGridSelArea.cpp | 240 +++ + src/qmaptool/overlay/gridtool/CGridSelArea.h | 97 + + src/qmaptool/overlay/gridtool/CGridSetRef.cpp | 105 + + src/qmaptool/overlay/gridtool/CGridSetRef.h | 86 + + src/qmaptool/overlay/gridtool/IGridPlacer.ui | 248 +++ + src/qmaptool/overlay/gridtool/IGridSelArea.ui | 49 + + src/qmaptool/overlay/gridtool/IGridSetRef.ui | 117 ++ + .../overlay/refmap/CDialogRefPoint.cpp | 74 + + src/qmaptool/overlay/refmap/CDialogRefPoint.h | 46 + + .../overlay/refmap/COverlayRefMapPoint.cpp | 52 + + .../overlay/refmap/COverlayRefMapPoint.h | 67 + + src/qmaptool/overlay/refmap/CProjWizard.cpp | 237 +++ + src/qmaptool/overlay/refmap/CProjWizard.h | 44 + + .../overlay/refmap/IDialogRefPoint.ui | 131 ++ + src/qmaptool/overlay/refmap/IProjWizard.ui | 210 ++ + src/qmaptool/resources.qrc | 93 + + src/qmaptool/setup/CAppOpts.h | 47 + + src/qmaptool/setup/CAppSetupLinux.cpp | 62 + + src/qmaptool/setup/CAppSetupLinux.h | 44 + + src/qmaptool/setup/CAppSetupMac.cpp | 140 ++ + src/qmaptool/setup/CAppSetupMac.h | 49 + + src/qmaptool/setup/CAppSetupWin.cpp | 69 + + src/qmaptool/setup/CAppSetupWin.h | 45 + + src/qmaptool/setup/CCommandProcessor.cpp | 58 + + src/qmaptool/setup/CCommandProcessor.h | 33 + + src/qmaptool/setup/CLogHandler.cpp | 122 ++ + src/qmaptool/setup/CLogHandler.h | 47 + + src/qmaptool/setup/CSetupExtTools.cpp | 93 + + src/qmaptool/setup/CSetupExtTools.h | 46 + + src/qmaptool/setup/IAppSetup.cpp | 161 ++ + src/qmaptool/setup/IAppSetup.h | 210 ++ + src/qmaptool/setup/ISetupExtTools.ui | 360 ++++ + src/qmaptool/shell/CShell.cpp | 198 ++ + src/qmaptool/shell/CShell.h | 75 + + src/qmaptool/shell/CShellCmd.cpp | 27 + + src/qmaptool/shell/CShellCmd.h | 47 + + src/qmaptool/tool/CToolAddOverview.cpp | 225 +++ + src/qmaptool/tool/CToolAddOverview.h | 51 + + src/qmaptool/tool/CToolBox.cpp | 44 + + src/qmaptool/tool/CToolBox.h | 40 + + src/qmaptool/tool/CToolCutMap.cpp | 202 ++ + src/qmaptool/tool/CToolCutMap.h | 51 + + src/qmaptool/tool/CToolExport.cpp | 193 ++ + src/qmaptool/tool/CToolExport.h | 63 + + src/qmaptool/tool/CToolGrid.cpp | 124 ++ + src/qmaptool/tool/CToolGrid.h | 57 + + src/qmaptool/tool/CToolOverviewGroupBox.cpp | 95 + + src/qmaptool/tool/CToolOverviewGroupBox.h | 43 + + src/qmaptool/tool/CToolPalettize.cpp | 319 +++ + src/qmaptool/tool/CToolPalettize.h | 57 + + src/qmaptool/tool/CToolRefMap.cpp | 257 +++ + src/qmaptool/tool/CToolRefMap.h | 52 + + src/qmaptool/tool/CToolStack.cpp | 44 + + src/qmaptool/tool/CToolStack.h | 41 + + src/qmaptool/tool/ITool.cpp | 20 + + src/qmaptool/tool/ITool.h | 234 +++ + src/qmaptool/tool/IToolAddOverview.ui | 278 +++ + src/qmaptool/tool/IToolCutMap.ui | 263 +++ + src/qmaptool/tool/IToolExport.ui | 206 ++ + src/qmaptool/tool/IToolGrid.ui | 158 ++ + src/qmaptool/tool/IToolGui.cpp | 111 ++ + src/qmaptool/tool/IToolGui.h | 48 + + src/qmaptool/tool/IToolOverviewGroupBox.ui | 130 ++ + src/qmaptool/tool/IToolPalettize.ui | 269 +++ + src/qmaptool/tool/IToolRefMap.ui | 276 +++ + src/qmaptool/tool/export/CToolExportJnx.cpp | 28 + + src/qmaptool/tool/export/CToolExportJnx.h | 68 + + src/qmaptool/tool/export/IToolExportJnx.ui | 224 +++ + src/qmaptool/units/CCoordFormatSetup.cpp | 67 + + src/qmaptool/units/CCoordFormatSetup.h | 37 + + src/qmaptool/units/CTimeZoneSetup.cpp | 105 + + src/qmaptool/units/CTimeZoneSetup.h | 36 + + src/qmaptool/units/CUnitImperial.cpp | 113 ++ + src/qmaptool/units/CUnitImperial.h | 41 + + src/qmaptool/units/CUnitMetric.cpp | 132 ++ + src/qmaptool/units/CUnitMetric.h | 37 + + src/qmaptool/units/CUnitNautic.cpp | 96 + + src/qmaptool/units/CUnitNautic.h | 37 + + src/qmaptool/units/CUnitsSetup.cpp | 59 + + src/qmaptool/units/CUnitsSetup.h | 35 + + src/qmaptool/units/ICoordFormatSetup.ui | 125 ++ + src/qmaptool/units/ITimeZoneSetup.ui | 182 ++ + src/qmaptool/units/IUnit.cpp | 776 ++++++++ + src/qmaptool/units/IUnit.h | 153 ++ + src/qmaptool/units/IUnitsSetup.ui | 125 ++ + src/qmaptool/version.h | 33 + + 154 files changed, 24277 insertions(+) + create mode 100644 src/qmaptool/.hgtags + create mode 100644 src/qmaptool/CAbout.cpp + create mode 100644 src/qmaptool/CAbout.h + create mode 100644 src/qmaptool/CMainWindow.cpp + create mode 100644 src/qmaptool/CMainWindow.h + create mode 100644 src/qmaptool/CMakeLists.txt + create mode 100644 src/qmaptool/CSingleInstanceProxy.cpp + create mode 100644 src/qmaptool/CSingleInstanceProxy.h + create mode 100644 src/qmaptool/GeoMath.cpp + create mode 100644 src/qmaptool/GeoMath.h + create mode 100644 src/qmaptool/IAbout.ui + create mode 100644 src/qmaptool/IMainWindow.ui + create mode 100644 src/qmaptool/README.md + create mode 100644 src/qmaptool/canvas/CCanvas.cpp + create mode 100644 src/qmaptool/canvas/CCanvas.h + create mode 100644 src/qmaptool/canvas/CDrawContextPixel.cpp + create mode 100644 src/qmaptool/canvas/CDrawContextPixel.h + create mode 100644 src/qmaptool/canvas/CDrawContextProj.cpp + create mode 100644 src/qmaptool/canvas/CDrawContextProj.h + create mode 100644 src/qmaptool/canvas/IDrawContext.cpp + create mode 100644 src/qmaptool/canvas/IDrawContext.h + create mode 100644 src/qmaptool/helpers/CDraw.cpp + create mode 100644 src/qmaptool/helpers/CDraw.h + create mode 100644 src/qmaptool/helpers/CGdalFile.cpp + create mode 100644 src/qmaptool/helpers/CGdalFile.h + create mode 100644 src/qmaptool/helpers/CSettings.h + create mode 100644 src/qmaptool/helpers/mitab.cpp + create mode 100644 src/qmaptool/helpers/mitab.h + create mode 100644 src/qmaptool/items/CItemCutMap.cpp + create mode 100644 src/qmaptool/items/CItemCutMap.h + create mode 100644 src/qmaptool/items/CItemFile.cpp + create mode 100644 src/qmaptool/items/CItemFile.h + create mode 100644 src/qmaptool/items/CItemListWidget.cpp + create mode 100644 src/qmaptool/items/CItemListWidget.h + create mode 100644 src/qmaptool/items/CItemMap.cpp + create mode 100644 src/qmaptool/items/CItemMap.h + create mode 100644 src/qmaptool/items/CItemMapLayer.cpp + create mode 100644 src/qmaptool/items/CItemMapLayer.h + create mode 100644 src/qmaptool/items/CItemRefMap.cpp + create mode 100644 src/qmaptool/items/CItemRefMap.h + create mode 100644 src/qmaptool/items/CItemTreeWidget.cpp + create mode 100644 src/qmaptool/items/CItemTreeWidget.h + create mode 100644 src/qmaptool/items/IItem.cpp + create mode 100644 src/qmaptool/items/IItem.h + create mode 100644 src/qmaptool/items/IItemListWidget.ui + create mode 100644 src/qmaptool/items/IItemTreeWidget.ui + create mode 100644 src/qmaptool/locale/qmaptool.ts + create mode 100644 src/qmaptool/locale/qmaptool_de.ts + create mode 100644 src/qmaptool/locale/qmaptool_es.ts + create mode 100644 src/qmaptool/main.cpp + create mode 100644 src/qmaptool/overlay/COverlayCutMap.cpp + create mode 100644 src/qmaptool/overlay/COverlayCutMap.h + create mode 100644 src/qmaptool/overlay/COverlayGridTool.cpp + create mode 100644 src/qmaptool/overlay/COverlayGridTool.h + create mode 100644 src/qmaptool/overlay/COverlayRefMap.cpp + create mode 100644 src/qmaptool/overlay/COverlayRefMap.h + create mode 100644 src/qmaptool/overlay/IOverlay.cpp + create mode 100644 src/qmaptool/overlay/IOverlay.h + create mode 100644 src/qmaptool/overlay/IOverlayCutMap.ui + create mode 100644 src/qmaptool/overlay/IOverlayGridTool.ui + create mode 100644 src/qmaptool/overlay/IOverlayRefMap.ui + create mode 100644 src/qmaptool/overlay/gridtool/CGridPlacer.cpp + create mode 100644 src/qmaptool/overlay/gridtool/CGridPlacer.h + create mode 100644 src/qmaptool/overlay/gridtool/CGridPoint.cpp + create mode 100644 src/qmaptool/overlay/gridtool/CGridPoint.h + create mode 100644 src/qmaptool/overlay/gridtool/CGridSelArea.cpp + create mode 100644 src/qmaptool/overlay/gridtool/CGridSelArea.h + create mode 100644 src/qmaptool/overlay/gridtool/CGridSetRef.cpp + create mode 100644 src/qmaptool/overlay/gridtool/CGridSetRef.h + create mode 100644 src/qmaptool/overlay/gridtool/IGridPlacer.ui + create mode 100644 src/qmaptool/overlay/gridtool/IGridSelArea.ui + create mode 100644 src/qmaptool/overlay/gridtool/IGridSetRef.ui + create mode 100644 src/qmaptool/overlay/refmap/CDialogRefPoint.cpp + create mode 100644 src/qmaptool/overlay/refmap/CDialogRefPoint.h + create mode 100644 src/qmaptool/overlay/refmap/COverlayRefMapPoint.cpp + create mode 100644 src/qmaptool/overlay/refmap/COverlayRefMapPoint.h + create mode 100644 src/qmaptool/overlay/refmap/CProjWizard.cpp + create mode 100644 src/qmaptool/overlay/refmap/CProjWizard.h + create mode 100644 src/qmaptool/overlay/refmap/IDialogRefPoint.ui + create mode 100644 src/qmaptool/overlay/refmap/IProjWizard.ui + create mode 100644 src/qmaptool/resources.qrc + create mode 100644 src/qmaptool/setup/CAppOpts.h + create mode 100644 src/qmaptool/setup/CAppSetupLinux.cpp + create mode 100644 src/qmaptool/setup/CAppSetupLinux.h + create mode 100644 src/qmaptool/setup/CAppSetupMac.cpp + create mode 100644 src/qmaptool/setup/CAppSetupMac.h + create mode 100644 src/qmaptool/setup/CAppSetupWin.cpp + create mode 100644 src/qmaptool/setup/CAppSetupWin.h + create mode 100644 src/qmaptool/setup/CCommandProcessor.cpp + create mode 100644 src/qmaptool/setup/CCommandProcessor.h + create mode 100644 src/qmaptool/setup/CLogHandler.cpp + create mode 100644 src/qmaptool/setup/CLogHandler.h + create mode 100644 src/qmaptool/setup/CSetupExtTools.cpp + create mode 100644 src/qmaptool/setup/CSetupExtTools.h + create mode 100644 src/qmaptool/setup/IAppSetup.cpp + create mode 100644 src/qmaptool/setup/IAppSetup.h + create mode 100644 src/qmaptool/setup/ISetupExtTools.ui + create mode 100644 src/qmaptool/shell/CShell.cpp + create mode 100644 src/qmaptool/shell/CShell.h + create mode 100644 src/qmaptool/shell/CShellCmd.cpp + create mode 100644 src/qmaptool/shell/CShellCmd.h + create mode 100644 src/qmaptool/tool/CToolAddOverview.cpp + create mode 100644 src/qmaptool/tool/CToolAddOverview.h + create mode 100644 src/qmaptool/tool/CToolBox.cpp + create mode 100644 src/qmaptool/tool/CToolBox.h + create mode 100644 src/qmaptool/tool/CToolCutMap.cpp + create mode 100644 src/qmaptool/tool/CToolCutMap.h + create mode 100644 src/qmaptool/tool/CToolExport.cpp + create mode 100644 src/qmaptool/tool/CToolExport.h + create mode 100644 src/qmaptool/tool/CToolGrid.cpp + create mode 100644 src/qmaptool/tool/CToolGrid.h + create mode 100644 src/qmaptool/tool/CToolOverviewGroupBox.cpp + create mode 100644 src/qmaptool/tool/CToolOverviewGroupBox.h + create mode 100644 src/qmaptool/tool/CToolPalettize.cpp + create mode 100644 src/qmaptool/tool/CToolPalettize.h + create mode 100644 src/qmaptool/tool/CToolRefMap.cpp + create mode 100644 src/qmaptool/tool/CToolRefMap.h + create mode 100644 src/qmaptool/tool/CToolStack.cpp + create mode 100644 src/qmaptool/tool/CToolStack.h + create mode 100644 src/qmaptool/tool/ITool.cpp + create mode 100644 src/qmaptool/tool/ITool.h + create mode 100644 src/qmaptool/tool/IToolAddOverview.ui + create mode 100644 src/qmaptool/tool/IToolCutMap.ui + create mode 100644 src/qmaptool/tool/IToolExport.ui + create mode 100644 src/qmaptool/tool/IToolGrid.ui + create mode 100644 src/qmaptool/tool/IToolGui.cpp + create mode 100644 src/qmaptool/tool/IToolGui.h + create mode 100644 src/qmaptool/tool/IToolOverviewGroupBox.ui + create mode 100644 src/qmaptool/tool/IToolPalettize.ui + create mode 100644 src/qmaptool/tool/IToolRefMap.ui + create mode 100644 src/qmaptool/tool/export/CToolExportJnx.cpp + create mode 100644 src/qmaptool/tool/export/CToolExportJnx.h + create mode 100644 src/qmaptool/tool/export/IToolExportJnx.ui + create mode 100644 src/qmaptool/units/CCoordFormatSetup.cpp + create mode 100644 src/qmaptool/units/CCoordFormatSetup.h + create mode 100644 src/qmaptool/units/CTimeZoneSetup.cpp + create mode 100644 src/qmaptool/units/CTimeZoneSetup.h + create mode 100644 src/qmaptool/units/CUnitImperial.cpp + create mode 100644 src/qmaptool/units/CUnitImperial.h + create mode 100644 src/qmaptool/units/CUnitMetric.cpp + create mode 100644 src/qmaptool/units/CUnitMetric.h + create mode 100644 src/qmaptool/units/CUnitNautic.cpp + create mode 100644 src/qmaptool/units/CUnitNautic.h + create mode 100644 src/qmaptool/units/CUnitsSetup.cpp + create mode 100644 src/qmaptool/units/CUnitsSetup.h + create mode 100644 src/qmaptool/units/ICoordFormatSetup.ui + create mode 100644 src/qmaptool/units/ITimeZoneSetup.ui + create mode 100644 src/qmaptool/units/IUnit.cpp + create mode 100644 src/qmaptool/units/IUnit.h + create mode 100644 src/qmaptool/units/IUnitsSetup.ui + create mode 100644 src/qmaptool/version.h + +diff --git a/src/qmaptool/.hgtags b/src/qmaptool/.hgtags +new file mode 100644 +index 00000000..b3bd51f1 +--- /dev/null ++++ b/src/qmaptool/.hgtags +@@ -0,0 +1 @@ ++ed93a4558565182ee15572442250f22981d3de56 V 1.1.0 +diff --git a/src/qmaptool/CAbout.cpp b/src/qmaptool/CAbout.cpp +new file mode 100644 +index 00000000..6c3c2cec +--- /dev/null ++++ b/src/qmaptool/CAbout.cpp +@@ -0,0 +1,46 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "CAbout.h" ++#include "version.h" ++ ++#include ++#include ++#include ++ ++ ++CAbout::CAbout(QWidget *parent) ++ : QDialog(parent) ++{ ++ setupUi(this); ++ ++ if(QString(VER_SUFFIX).isEmpty()) ++ { ++ labelVersion->setText(VER_STR); ++ } ++ else ++ { ++ labelVersion->setText(VER_STR "." VER_SUFFIX); ++ } ++ ++ labelQtVersion->setText(qVersion()); ++ labelGDALVersion->setText(GDALVersionInfo("--version")); ++ labelProj4Version->setText(QString::number(PJ_VERSION)); ++} ++ ++ +diff --git a/src/qmaptool/CAbout.h b/src/qmaptool/CAbout.h +new file mode 100644 +index 00000000..52a6bfd7 +--- /dev/null ++++ b/src/qmaptool/CAbout.h +@@ -0,0 +1,35 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CABOUT_H ++#define CABOUT_H ++ ++#include "ui_IAbout.h" ++#include ++ ++ ++class CAbout : public QDialog, private Ui::IAbout ++{ ++ Q_OBJECT ++public: ++ CAbout(QWidget * parent); ++ virtual ~CAbout() = default; ++}; ++ ++#endif //CABOUT_H ++ +diff --git a/src/qmaptool/CMainWindow.cpp b/src/qmaptool/CMainWindow.cpp +new file mode 100644 +index 00000000..c21b566b +--- /dev/null ++++ b/src/qmaptool/CMainWindow.cpp +@@ -0,0 +1,182 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "CAbout.h" ++#include "CMainWindow.h" ++#include "helpers/CSettings.h" ++#include "setup/CSetupExtTools.h" ++#include "tool/CToolAddOverview.h" ++#include "tool/CToolBox.h" ++#include "tool/CToolCutMap.h" ++#include "tool/CToolExport.h" ++#include "tool/CToolGrid.h" ++#include "tool/CToolPalettize.h" ++#include "tool/CToolRefMap.h" ++#include "units/CCoordFormatSetup.h" ++#include "units/CUnitsSetup.h" ++#include "units/IUnit.h" ++#include "version.h" ++ ++CMainWindow * CMainWindow::pSelf = nullptr; ++ ++CMainWindow::CMainWindow() ++{ ++ SETTINGS; ++ IUnit::setUnitType((IUnit::type_e)cfg.value("Units/units",IUnit::eTypeMetric).toInt(), this); ++ IUnit::setCoordFormat((IUnit::coord_format_e)cfg.value("Units/coordFormat", IUnit::eCoordFormat1).toInt()); ++ ++ pSelf = this; ++ setupUi(this); ++ setWindowTitle(WHAT_STR); ++ ++ canvas->setToolInterface(toolStack); ++ ++ connect(actionAbout, &QAction::triggered, this, &CMainWindow::slotAbout); ++ connect(actionSetupExtTools, &QAction::triggered, this, &CMainWindow::slotSetupExtTools); ++ connect(actionSetupUnits, &QAction::triggered, this, &CMainWindow::slotSetupUnits); ++ connect(actionSetupCoordFormat, &QAction::triggered, this, &CMainWindow::slotSetupCoordFormat); ++ connect(&IAppSetup::self(), &IAppSetup::sigSetupChanged, this, &CMainWindow::slotSetupChanged); ++ ++ menuWindow->addAction(dockTools->toggleViewAction()); ++ menuWindow->addAction(dockShell->toggleViewAction()); ++ prepareMenuForMac(); ++ ++ toolBox = new CToolBox(this); ++ toolStack->addWidget(toolBox); ++ ++ toolAddOverview = new CToolAddOverview(toolBox); ++ toolBox->addItem(toolAddOverview, QIcon("://icons/32x32/AddOverview.png"), toolAddOverview->objectName()); ++ ++ toolCutMap = new CToolCutMap(toolBox); ++ toolBox->addItem(toolCutMap, QIcon("://icons/32x32/CutMap.png"), toolCutMap->objectName()); ++ ++ toolRefMap = new CToolRefMap(toolBox); ++ toolBox->addItem(toolRefMap, QIcon("://icons/32x32/ReferenceMap.png"), toolRefMap->objectName()); ++ ++ toolPalettize = new CToolPalettize(toolBox); ++ toolBox->addItem(toolPalettize, QIcon("://icons/32x32/Rasterize.png"), toolPalettize->objectName()); ++ ++ toolExport = new CToolExport(toolBox); ++ toolBox->addItem(toolExport, QIcon("://icons/32x32/Export.png"), toolExport->objectName()); ++ ++ toolGrid = new CToolGrid(this); ++ toolStack->addWidget(toolGrid); ++ ++ // start ---- restore window geometry ----- ++ if ( cfg.contains("MainWindow/geometry")) ++ { ++ restoreGeometry(cfg.value("MainWindow/geometry").toByteArray()); ++ } ++ else ++ { ++ QTimer::singleShot(500, this, SLOT(showMaximized())); ++ } ++ ++ if ( cfg.contains("MainWindow/state")) ++ { ++ restoreState(cfg.value("MainWindow/state").toByteArray()); ++ } ++ // end ---- restore window geometry ----- ++ //toolStack->setCurrentIndex(cfg.value("Tool/Stack/current",0).toInt()); ++ toolBox->setCurrentIndex(cfg.value("Tool/Box/current",0).toInt()); ++ actionShowToolHelp->setChecked(cfg.value("Tool/showHelp", true).toBool()); ++ mapFont = cfg.value("Canvas/mapFont", font()).value(); ++ actionFlipMouseWheel->setChecked(cfg.value("Canvas/flipMouseWheel", false).toBool()); ++} ++ ++CMainWindow::~CMainWindow() ++{ ++ SETTINGS; ++ cfg.setValue("MainWindow/state", saveState()); ++ cfg.setValue("MainWindow/geometry", saveGeometry()); ++ ++ cfg.setValue("Canvas/mapFont", mapFont); ++ cfg.setValue("Canvas/flipMouseWheel", actionFlipMouseWheel->isChecked()); ++ ++ cfg.setValue("Units/units", IUnit::self().type); ++ cfg.setValue("Units/coordFormat", IUnit::getCoordFormat()); ++ ++ cfg.setValue("Tool/Box/current", toolBox->currentIndex()); ++ cfg.setValue("Tool/showHelp", actionShowToolHelp->isChecked()); ++} ++ ++QString CMainWindow::getUser() ++{ ++ QString user = getenv("USER"); ++ if(user.isEmpty()) ++ { ++ user = getenv("USERNAME"); //for windows ++ ++ if(user.isEmpty()) ++ { ++ user = "QMapTool"; ++ } ++ } ++ ++ return user; ++} ++ ++void CMainWindow::prepareMenuForMac() ++{ ++ dockTools->toggleViewAction()->setMenuRole(QAction::NoRole); ++} ++ ++void CMainWindow::makeShellVisible() ++{ ++ dockShell->show(); ++} ++ ++void CMainWindow::startGridTool(CItemRefMap *item) ++{ ++ toolGrid->registerItem(item); ++ toolStack->setCurrentWidget(toolGrid); ++} ++ ++void CMainWindow::showToolBox() ++{ ++ toolStack->setCurrentWidget(toolBox); ++} ++ ++void CMainWindow::slotAbout() ++{ ++ CAbout dlg(this); ++ dlg.exec(); ++} ++ ++void CMainWindow::slotSetupExtTools() ++{ ++ CSetupExtTools dlg(this); ++ dlg.exec(); ++} ++ ++void CMainWindow::slotSetupUnits() ++{ ++ CUnitsSetup dlg(this); ++ dlg.exec(); ++} ++ ++void CMainWindow::slotSetupCoordFormat() ++{ ++ CCoordFormatSetup dlg(this); ++ dlg.exec(); ++} ++ ++void CMainWindow::slotSetupChanged() ++{ ++ toolStack->setupChanged(); ++} +diff --git a/src/qmaptool/CMainWindow.h b/src/qmaptool/CMainWindow.h +new file mode 100644 +index 00000000..40077106 +--- /dev/null ++++ b/src/qmaptool/CMainWindow.h +@@ -0,0 +1,100 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CMAINWINDOW_H ++#define CMAINWINDOW_H ++ ++#include "ui_IMainWindow.h" ++#include ++ ++class CToolBox; ++class CToolAddOverview; ++class CToolCutMap; ++class CToolRefMap; ++class CToolPalettize; ++class CCanvas; ++class CToolGrid; ++class CItemRefMap; ++class CToolExport; ++ ++class CMainWindow : public QMainWindow, private Ui::IMainWindow ++{ ++ Q_OBJECT ++public: ++ static CMainWindow& self() ++ { ++ return *pSelf; ++ } ++ ++ virtual ~CMainWindow(); ++ ++ static QString getUser(); ++ ++ CCanvas * getCanvas() const ++ { ++ return canvas; ++ } ++ ++ const QFont& getMapFont() const ++ { ++ return mapFont; ++ } ++ ++ bool flipMouseWheel() const ++ { ++ return actionFlipMouseWheel->isChecked(); ++ } ++ ++ QAction * showToolHelp() const ++ { ++ return actionShowToolHelp; ++ } ++ ++ void makeShellVisible(); ++ ++ void startGridTool(CItemRefMap * item); ++ void showToolBox(); ++ ++private slots: ++ void slotAbout(); ++ void slotSetupExtTools(); ++ void slotSetupUnits(); ++ void slotSetupCoordFormat(); ++ void slotSetupChanged(); ++ ++private: ++ friend int main(int argc, char ** argv); ++ CMainWindow(); ++ static CMainWindow * pSelf; ++ ++ void prepareMenuForMac(); ++ ++ QFont mapFont; ++ ++ CToolBox * toolBox; ++ CToolGrid * toolGrid; ++ ++ CToolAddOverview * toolAddOverview; ++ CToolCutMap * toolCutMap; ++ CToolRefMap * toolRefMap; ++ CToolPalettize * toolPalettize; ++ CToolExport * toolExport; ++}; ++ ++#endif //CMAINWINDOW_H ++ +diff --git a/src/qmaptool/CMakeLists.txt b/src/qmaptool/CMakeLists.txt +new file mode 100644 +index 00000000..5fd64152 +--- /dev/null ++++ b/src/qmaptool/CMakeLists.txt +@@ -0,0 +1,269 @@ ++# Prevent custom commands/targets outputs to be deleted by make clean ++# We need this to prevent .ts files from being deleted with make clean, when ++# UPDATE_TRANSLATIONS=ON ++# WARNING: Only works with Makefile generator. ++set_directory_properties(PROPERTIES CLEAN_NO_CUSTOM TRUE) ++# Find includes in corresponding build directories ++set(CMAKE_INCLUDE_CURRENT_DIR ON) ++# Instruct CMake to run moc automatically when needed. ++set(CMAKE_AUTOMOC ON) ++ ++############################################################################################### ++# Setup application name and version tags ++############################################################################################### ++ ++set(APPLICATION_NAME qmaptool) ++set(QMAPTOOL_VERSION_MAJOR 1) ++set(QMAPTOOL_VERSION_MINOR 1) ++set(QMAPTOOL_VERSION_PATCH 1) ++ ++add_definitions( ++ -DVER_MAJOR=${QMAPTOOL_VERSION_MAJOR} ++ -DVER_MINOR=${QMAPTOOL_VERSION_MINOR} ++ -DVER_STEP=${QMAPTOOL_VERSION_PATCH} ++ -DVER_TWEAK=${VERSION_SUFFIX} ++ -DAPPLICATION_NAME=${APPLICATION_NAME} ++) ++ ++############################################################################################### ++# All source files needed to compile ++############################################################################################### ++set( SRCS ++ CAbout.cpp ++ canvas/CCanvas.cpp ++ canvas/CDrawContextPixel.cpp ++ canvas/CDrawContextProj.cpp ++ canvas/IDrawContext.cpp ++ CMainWindow.cpp ++ CSingleInstanceProxy.cpp ++ GeoMath.cpp ++ helpers/CDraw.cpp ++ helpers/CGdalFile.cpp ++ helpers/mitab.cpp ++ items/CItemCutMap.cpp ++ items/CItemFile.cpp ++ items/CItemListWidget.cpp ++ items/CItemMap.cpp ++ items/CItemMapLayer.cpp ++ items/CItemRefMap.cpp ++ items/CItemTreeWidget.cpp ++ items/IItem.cpp ++ main.cpp ++ overlay/COverlayCutMap.cpp ++ overlay/COverlayGridTool.cpp ++ overlay/COverlayRefMap.cpp ++ overlay/gridtool/CGridPlacer.cpp ++ overlay/gridtool/CGridPoint.cpp ++ overlay/gridtool/CGridSelArea.cpp ++ overlay/gridtool/CGridSetRef.cpp ++ overlay/IOverlay.cpp ++ overlay/refmap/CDialogRefPoint.cpp ++ overlay/refmap/COverlayRefMapPoint.cpp ++ overlay/refmap/CProjWizard.cpp ++ setup/CAppSetupLinux.cpp ++ setup/CAppSetupMac.cpp ++ setup/CAppSetupWin.cpp ++ setup/CCommandProcessor.cpp ++ setup/CLogHandler.cpp ++ setup/CSetupExtTools.cpp ++ setup/IAppSetup.cpp ++ shell/CShellCmd.cpp ++ shell/CShell.cpp ++ tool/export/CToolExportJnx.cpp ++ tool/CToolAddOverview.cpp ++ tool/CToolBox.cpp ++ tool/CToolCutMap.cpp ++ tool/CToolExport.cpp ++ tool/CToolGrid.cpp ++ tool/CToolOverviewGroupBox.cpp ++ tool/CToolPalettize.cpp ++ tool/CToolRefMap.cpp ++ tool/CToolStack.cpp ++ tool/ITool.cpp ++ tool/IToolGui.cpp ++ units/CCoordFormatSetup.cpp ++ units/CTimeZoneSetup.cpp ++ units/CUnitImperial.cpp ++ units/CUnitMetric.cpp ++ units/CUnitNautic.cpp ++ units/CUnitsSetup.cpp ++ units/IUnit.cpp ++) ++ ++set( HDRS ++ CAbout.h ++ canvas/CCanvas.h ++ canvas/CDrawContextPixel.h ++ canvas/CDrawContextProj.h ++ canvas/IDrawContext.h ++ CMainWindow.h ++ CSingleInstanceProxy.h ++ GeoMath.h ++ helpers/CDraw.h ++ helpers/CGdalFile.h ++ helpers/CSettings.h ++ helpers/CSettings.h ++ helpers/mitab.h ++ items/CItemCutMap.h ++ items/CItemFile.h ++ items/CItemListWidget.h ++ items/CItemMap.h ++ items/CItemMapLayer.h ++ items/CItemRefMap.h ++ items/CItemTreeWidget.h ++ items/IItem.h ++ overlay/COverlayCutMap.h ++ overlay/COverlayGridTool.h ++ overlay/COverlayRefMap.h ++ overlay/gridtool/CGridPlacer.h ++ overlay/gridtool/CGridPoint.h ++ overlay/gridtool/CGridSelArea.h ++ overlay/gridtool/CGridSetRef.h ++ overlay/IOverlay.h ++ overlay/refmap/CDialogRefPoint.h ++ overlay/refmap/COverlayRefMapPoint.h ++ overlay/refmap/CProjWizard.h ++ setup/CAppOpts.h ++ setup/CAppSetupLinux.h ++ setup/CAppSetupMac.h ++ setup/CAppSetupWin.h ++ setup/CCommandProcessor.h ++ setup/CLogHandler.h ++ setup/CSetupExtTools.h ++ setup/IAppSetup.h ++ shell/CShellCmd.h ++ shell/CShell.h ++ tool/export/CToolExportJnx.h ++ tool/CToolAddOverview.h ++ tool/CToolBox.h ++ tool/CToolCutMap.h ++ tool/CToolExport.h ++ tool/CToolGrid.h ++ tool/CToolOverviewGroupBox.h ++ tool/CToolPalettize.h ++ tool/CToolRefMap.h ++ tool/CToolStack.h ++ tool/IToolGui.h ++ tool/ITool.h ++ units/CCoordFormatSetup.h ++ units/CTimeZoneSetup.h ++ units/CUnitImperial.h ++ units/CUnitMetric.h ++ units/CUnitNautic.h ++ units/CUnitsSetup.h ++ units/IUnit.h ++ version.h ++) ++ ++set( UIS ++ IAbout.ui ++ IMainWindow.ui ++ items/IItemListWidget.ui ++ items/IItemTreeWidget.ui ++ overlay/gridtool/IGridPlacer.ui ++ overlay/gridtool/IGridSelArea.ui ++ overlay/gridtool/IGridSetRef.ui ++ overlay/IOverlayCutMap.ui ++ overlay/IOverlayGridTool.ui ++ overlay/IOverlayRefMap.ui ++ overlay/refmap/IDialogRefPoint.ui ++ overlay/refmap/IProjWizard.ui ++ setup/ISetupExtTools.ui ++ tool/export/IToolExportJnx.ui ++ tool/IToolAddOverview.ui ++ tool/IToolCutMap.ui ++ tool/IToolExport.ui ++ tool/IToolGrid.ui ++ tool/IToolOverviewGroupBox.ui ++ tool/IToolPalettize.ui ++ tool/IToolRefMap.ui ++ units/ICoordFormatSetup.ui ++ units/ITimeZoneSetup.ui ++ units/IUnitsSetup.ui ++) ++ ++ ++set( RCS ++ resources.qrc ++) ++ ++ ++############################################################################################### ++# Some Qt magic ++############################################################################################### ++ ++qt5_wrap_ui(UI_HDRS ${UIS}) ++qt5_add_resources(RC_SRCS ${RCS}) ++ ++############################################################################################### ++# Translation related stuff ++############################################################################################### ++translate_ts(${APPLICATION_NAME}_QM_FILES ++ UPDATE_TRANSLATIONS ${UPDATE_TRANSLATIONS} ++ UPDATE_OPTIONS "-I${CMAKE_CURRENT_SOURCE_DIR}" ${KEEP_OLD_TRANSLATIONS} ++ SOURCES ${SRCS} ${HDRS} ${UIS} ++ TEMPLATE ${APPLICATION_NAME} ++ TRANSLATION_DIR "locale" ++) ++ ++if (UNIX AND NOT WIN32 AND NOT APPLE) ++ translate_desktop(${APPLICATION_NAME}_DESKTOP_FILES ++ TRANSLATION_DIR "locale" ++ SOURCES "${PROJECT_SOURCE_DIR}/qmaptool.desktop.in" ++ ) ++endif() ++ ++############################################################################################### ++# Build source file and include paths lists ++############################################################################################### ++set(MAININP ++ ${SRCS} ++ ${HDRS} ++ ${UI_HDRS} ++ ${RC_SRCS} ++ ${${APPLICATION_NAME}_QM_FILES} ++ ${${APPLICATION_NAME}_DESKTOP_FILES} ++) ++ ++include_directories( ++ SYSTEM # this prevents warnings from non-QMS headers ++ ${CMAKE_BINARY_DIR} ++ ${GDAL_INCLUDE_DIRS} ++ ${PROJ4_INCLUDE_DIRS} ++) ++ ++if(APPLE) ++ INCLUDE_DIRECTORIES(/System/Library/Frameworks/Foundation.framework) ++ INCLUDE_DIRECTORIES(/System/Library/Frameworks/DiskArbitration.framework) ++endif(APPLE) ++ ++ ++############################################################################################### ++# Build the executable and define necessary libraries. ++############################################################################################### ++add_executable(${APPLICATION_NAME} WIN32 ${MAININP}) ++ ++target_link_libraries(${APPLICATION_NAME} ++ Qt5::Widgets ++ Qt5::Network ++ ${GDAL_LIBRARIES} ++ ${PROJ4_LIBRARIES} ++) ++ ++if(APPLE) ++ target_link_libraries(${APPLICATION_NAME} ++ ${Foundation_LIBRARY} ++ ${DiskArbitration_LIBRARY} ++ ) ++endif(APPLE) ++ ++ ++############################################################################################### ++# Install target related stuff ++############################################################################################### ++install(TARGETS ${APPLICATION_NAME} DESTINATION ${BIN_INSTALL_DIR}) ++ ++if (UNIX AND NOT WIN32 AND NOT APPLE) ++ install(FILES ${${APPLICATION_NAME}_QM_FILES} DESTINATION ${DATA_INSTALL_PREFIX}/${APPLICATION_NAME}/translations) ++ install(FILES ${${APPLICATION_NAME}_DESKTOP_FILES} DESTINATION ${XDG_APPS_DIR}) ++endif (UNIX AND NOT WIN32 AND NOT APPLE) +diff --git a/src/qmaptool/CSingleInstanceProxy.cpp b/src/qmaptool/CSingleInstanceProxy.cpp +new file mode 100644 +index 00000000..58cc933e +--- /dev/null ++++ b/src/qmaptool/CSingleInstanceProxy.cpp +@@ -0,0 +1,102 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "CMainWindow.h" ++#include "CSingleInstanceProxy.h" ++#include ++ ++CSingleInstanceProxy::CSingleInstanceProxy(const QStringList filenames) ++{ ++ serverName = CMainWindow::self().getUser(); ++ if(serverName != "QMapTool") ++ { ++ serverName = "QMapTool-" + serverName; ++ } ++ ++ QLocalSocket socket; ++ socket.connectToServer(serverName); ++ if(socket.waitForConnected(1000)) ++ { ++ // if the connection is successful another instance ++ // is already running. In that case the list of files to ++ // open is sent to the primary instance. And this instance ++ // will be closed imediately. ++ QDataStream stream(&socket); ++ stream << filenames; ++ socket.waitForBytesWritten(3000); ++ ++ // wait for confirmation ++ socket.waitForReadyRead(3000); ++ bool ok; ++ stream >> ok; ++ qDebug() << "Sent parameters to primary instance. Result" << ok; ++ qDebug() << "There can only be one. Exit."; ++ exit(0); ++ } ++ ++ // Looks like we are the first instance. ++ // Create a server socket and wait for other instances to connect. ++ server = new QLocalServer(this); ++ connect(server, &QLocalServer::newConnection, this, &CSingleInstanceProxy::slotNewConnection); ++ server->removeServer(serverName); ++ if(!server->listen(serverName)) ++ { ++ qDebug() << "CSingleInstanceProxy: Failed to start single instance server socket."; ++ } ++ else ++ { ++ qDebug() << "CSingleInstanceProxy: Single instance server socket listening to" << server->fullServerName(); ++ } ++} ++ ++CSingleInstanceProxy::~CSingleInstanceProxy() ++{ ++ qDebug() << "CSingleInstanceProxy::~CSingleInstanceProxy()"; ++} ++ ++void CSingleInstanceProxy::slotNewConnection() ++{ ++ QLocalSocket * socket = server->nextPendingConnection(); ++ if(socket == nullptr) ++ { ++ return; ++ } ++ ++ // Each secondary instance will send a QStringList with files to open ++ // The list can be empty. ++ if(socket->waitForReadyRead(3000)) ++ { ++ QStringList filenames; ++ QDataStream stream(socket); ++ stream >> filenames; ++ ++ CMainWindow& w = CMainWindow::self(); ++ //w.loadGISData(filenames); ++ ++ // confirm that files are loaded ++ stream << true; ++ socket->waitForBytesWritten(3000); ++ ++ // raise the application window to top of desktop ++ w.raise(); ++ QApplication::setActiveWindow(&w); ++ } ++ ++ socket->close(); ++ delete socket; ++} +diff --git a/src/qmaptool/CSingleInstanceProxy.h b/src/qmaptool/CSingleInstanceProxy.h +new file mode 100644 +index 00000000..c211c8cb +--- /dev/null ++++ b/src/qmaptool/CSingleInstanceProxy.h +@@ -0,0 +1,41 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CSINGLEINSTANCEPROXY_H ++#define CSINGLEINSTANCEPROXY_H ++ ++#include ++class QLocalServer; ++ ++class CSingleInstanceProxy : public QObject ++{ ++public: ++ CSingleInstanceProxy(const QStringList filenames); ++ virtual ~CSingleInstanceProxy(); ++ ++private slots: ++ void slotNewConnection(); ++ ++private: ++ QLocalServer * server = nullptr; ++ ++ QString serverName; ++}; ++ ++#endif //CSINGLEINSTANCEPROXY_H ++ +diff --git a/src/qmaptool/GeoMath.cpp b/src/qmaptool/GeoMath.cpp +new file mode 100644 +index 00000000..00596006 +--- /dev/null ++++ b/src/qmaptool/GeoMath.cpp +@@ -0,0 +1,54 @@ ++/********************************************************************************************** ++ Copyright (C) 2009 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ ++**********************************************************************************************/ ++ ++#include "GeoMath.h" ++ ++#define PI M_PI ++#define TWOPI (2*PI) ++ ++ ++void GPS_Math_DegMinSec_To_Deg(bool sign, const qint32 d, const qint32 m, const qreal s, qreal °) ++{ ++ deg = qAbs(d) + qreal(m) / 60.0 + s / 3600; ++ if(sign) ++ { ++ deg = -deg; ++ } ++} ++ ++ ++bool GPS_Math_Deg_To_DegMin(qreal v, qint32 *deg, qreal *min) ++{ ++ *deg = qAbs(v); ++ *min = (qAbs(v) - *deg) * 60.0; ++ ++ return v < 0; ++} ++ ++ ++void GPS_Math_DegMin_To_Deg(bool sign, const qint32 d, const qreal m, qreal& deg) ++{ ++ deg = qAbs(d) + m / 60.0; ++ if(sign) ++ { ++ deg = -deg; ++ } ++} ++ ++ +diff --git a/src/qmaptool/GeoMath.h b/src/qmaptool/GeoMath.h +new file mode 100644 +index 00000000..7f48a1fe +--- /dev/null ++++ b/src/qmaptool/GeoMath.h +@@ -0,0 +1,31 @@ ++/********************************************************************************************** ++ Copyright (C) 2009 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ ++**********************************************************************************************/ ++ ++#ifndef GEOMATH_H ++#define GEOMATH_H ++ ++#include ++#include ++ ++void GPS_Math_DegMin_To_Deg(bool sign, const qint32 d, const qreal m, qreal& deg); ++void GPS_Math_DegMinSec_To_Deg(bool sign, const qint32 d, const qint32 m, const qreal s, qreal& deg); ++bool GPS_Math_Deg_To_DegMin(qreal v, qint32 *deg, qreal *min); ++ ++#endif //GEOMATH_H ++ +diff --git a/src/qmaptool/IAbout.ui b/src/qmaptool/IAbout.ui +new file mode 100644 +index 00000000..17d509bd +--- /dev/null ++++ b/src/qmaptool/IAbout.ui +@@ -0,0 +1,164 @@ ++ ++ ++ IAbout ++ ++ ++ ++ 0 ++ 0 ++ 418 ++ 407 ++ ++ ++ ++ About... ++ ++ ++ ++ :/icons/32x32/QMapTool.png:/icons/32x32/QMapTool.png ++ ++ ++ ++ ++ ++ ++ ++ <b>QMapTool</b>, Version ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ TextLabel ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ :/icons/48x48/QMapTool.png ++ ++ ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ ++ ++ ++ QFormLayout::AllNonFixedFieldsGrow ++ ++ ++ ++ ++ Qt ++ ++ ++ ++ ++ ++ ++ TextLabel ++ ++ ++ ++ ++ ++ ++ GDAL ++ ++ ++ ++ ++ ++ ++ TextLabel ++ ++ ++ ++ ++ ++ ++ Proj4 ++ ++ ++ ++ ++ ++ ++ TextLabel ++ ++ ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ ++ ++ ++ This software is licensed under GPL3 or any later version ++ ++ ++ ++ ++ ++ ++ © 2017 Oliver Eichler (oliver.eichler@gmx.de) ++ ++ ++ ++ ++ ++ ++ Qt::Vertical ++ ++ ++ ++ 20 ++ 40 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ :/pic/splash.png ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/src/qmaptool/IMainWindow.ui b/src/qmaptool/IMainWindow.ui +new file mode 100644 +index 00000000..6b11c3bb +--- /dev/null ++++ b/src/qmaptool/IMainWindow.ui +@@ -0,0 +1,208 @@ ++ ++ ++ IMainWindow ++ ++ ++ ++ 0 ++ 0 ++ 800 ++ 600 ++ ++ ++ ++ MainWindow ++ ++ ++ ++ :/icons/48x48/QMapTool.png:/icons/48x48/QMapTool.png ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ 800 ++ 23 ++ ++ ++ ++ ++ Setup ++ ++ ++ ++ ++ ++ ++ ++ ++ View ++ ++ ++ ++ ++ ++ Window ++ ++ ++ ++ ++ ? ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable|QDockWidget::DockWidgetVerticalTitleBar ++ ++ ++ Tools ++ ++ ++ 1 ++ ++ ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ QDockWidget::DockWidgetFeatureMask ++ ++ ++ Shell ++ ++ ++ 8 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ :/icons/32x32/Info.png:/icons/32x32/Info.png ++ ++ ++ About ++ ++ ++ ++ ++ ++ :/icons/32x32/Apply.png:/icons/32x32/Apply.png ++ ++ ++ Ext. Tools ++ ++ ++ Setup paths to external tools, like gdalwarp etc. ++ ++ ++ ++ ++ true ++ ++ ++ ++ :/icons/32x32/MouseWheel.png:/icons/32x32/MouseWheel.png ++ ++ ++ Flip Mouse Wheel ++ ++ ++ Flip Mouse Wheel ++ ++ ++ ++ ++ ++ :/icons/32x32/UnitSetup.png:/icons/32x32/UnitSetup.png ++ ++ ++ Setup Units ++ ++ ++ Setup Units ++ ++ ++ ++ ++ ++ :/icons/32x32/SetupCoordFormat.png:/icons/32x32/SetupCoordFormat.png ++ ++ ++ Setup Coord. Format ++ ++ ++ Change the format coordinates are displayed ++ ++ ++ ++ ++ true ++ ++ ++ true ++ ++ ++ Show Tool Help ++ ++ ++ ++ ++ ++ CShell ++ QTextBrowser ++
shell/CShell.h
++
++ ++ CCanvas ++ QWidget ++
canvas/CCanvas.h
++ 1 ++
++ ++ CToolStack ++ QStackedWidget ++
tool/CToolStack.h
++ 1 ++
++
++ ++ ++ ++ ++
+diff --git a/src/qmaptool/README.md b/src/qmaptool/README.md +new file mode 100644 +index 00000000..2db8ed98 +--- /dev/null ++++ b/src/qmaptool/README.md +@@ -0,0 +1,7 @@ ++# README # ++ ++This is a sub-project of QMapShack and it's not supposed to compile on it's own. Please refere to ++ ++https://bitbucket.org/maproom/qmapshack/overview ++ ++to check out and compile this project. +\ No newline at end of file +diff --git a/src/qmaptool/canvas/CCanvas.cpp b/src/qmaptool/canvas/CCanvas.cpp +new file mode 100644 +index 00000000..11b65e54 +--- /dev/null ++++ b/src/qmaptool/canvas/CCanvas.cpp +@@ -0,0 +1,189 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "canvas/CCanvas.h" ++#include "canvas/IDrawContext.h" ++#include "helpers/CDraw.h" ++ ++ ++#include ++ ++CCanvas::CCanvas(QWidget *parent) ++ : QWidget(parent) ++{ ++ setFocusPolicy(Qt::WheelFocus); ++ setMouseTracking(true); ++ ++ loadIndicator1 = new QMovie("://animation/loader.gif", QByteArray(), this); ++ mapLoadIndicator = new QLabel(this); ++ mapLoadIndicator->setMovie(loadIndicator1); ++ loadIndicator1->start(); ++ mapLoadIndicator->show(); ++} ++ ++void CCanvas::setOverrideCursor(const QCursor &cursor, const QString&) ++{ ++// qDebug() << "setOverrideCursor" << src; ++ QApplication::setOverrideCursor(cursor); ++} ++ ++void CCanvas::restoreOverrideCursor(const QString& src) ++{ ++// qDebug() << "restoreOverrideCursor" << src; ++ QApplication::restoreOverrideCursor(); ++} ++ ++void CCanvas::changeOverrideCursor(const QCursor& cursor, const QString &src) ++{ ++// qDebug() << "changeOverrideCursor" << src; ++ QApplication::changeOverrideCursor(cursor); ++} ++ ++ ++void CCanvas::resizeEvent(QResizeEvent *e) ++{ ++ QMutexLocker lock(&mutex); ++ ++ needsRedraw = eRedrawAll; ++ ++ // move map loading indicator to new center of canvas ++ QPoint p1(mapLoadIndicator->width()>>1, mapLoadIndicator->height()>>1); ++ mapLoadIndicator->move(rect().center() - p1); ++ ++ emit sigChangedSize(e->size()); ++ ++ QWidget::resizeEvent(e); ++} ++ ++void CCanvas::paintEvent(QPaintEvent *e) ++{ ++ QPainter p; ++ p.begin(this); ++ USE_ANTI_ALIASING(p,true); ++ ++ // fill the background with default pattern ++ p.fillRect(rect(), backColor); ++ ++ // ----- start to draw thread based content ----- ++ ++ mutex.lock(); ++ if(!tool->drawFx(p,needsRedraw)) ++ { ++ mutex.unlock(); ++ slotHideLoadIndicator(); ++ CDraw::text(tr("No map view available."), p, rect(), Qt::black); ++ mutex.lock(); ++ } ++ mutex.unlock(); ++ // ----- start to draw fast content ----- ++ p.end(); ++ needsRedraw = eRedrawNone; ++} ++ ++void CCanvas::mousePressEvent(QMouseEvent *e) ++{ ++ QMutexLocker lock(&mutex); ++ tool->mousePressEventFx(e); ++ e->accept(); ++} ++ ++void CCanvas::mouseMoveEvent(QMouseEvent *e) ++{ ++ QMutexLocker lock(&mutex); ++ tool->mouseMoveEventFx(e); ++ e->accept(); ++} ++ ++void CCanvas::mouseReleaseEvent(QMouseEvent *e) ++{ ++ QMutexLocker lock(&mutex); ++ tool->mouseReleaseEventFx(e); ++ e->accept(); ++} ++ ++void CCanvas::mouseDoubleClickEvent(QMouseEvent *e) ++{ ++ QMutexLocker lock(&mutex); ++ tool->mouseDoubleClickEventFx(e); ++ e->accept(); ++} ++ ++void CCanvas::wheelEvent(QWheelEvent *e) ++{ ++ QMutexLocker lock(&mutex); ++ tool->wheelEventFx(e); ++} ++ ++void CCanvas::enterEvent(QEvent *e) ++{ ++ QMutexLocker lock(&mutex); ++ ++ tool->enterEventFx(e); ++ CCanvas::setOverrideCursor(tool->getCursorFx(), "enterEvent"); ++ ++ setMouseTracking(true); ++} ++ ++void CCanvas::leaveEvent(QEvent *e) ++{ ++ QMutexLocker lock(&mutex); ++ ++ tool->leaveEventFx(e); ++ ++ // bad hack to stop bad number of override cursors. ++ while(QApplication::overrideCursor()) ++ { ++ CCanvas::restoreOverrideCursor("leaveEvent"); ++ } ++ ++ ++ setMouseTracking(false); ++} ++ ++void CCanvas::keyPressEvent(QKeyEvent *e) ++{ ++ QMutexLocker lock(&mutex); ++ if(!tool->keyPressEventFx(e)) ++ { ++ e->ignore(); ++ } ++} ++ ++ ++void CCanvas::slotTriggerCompleteUpdate(CCanvas::redraw_e flags) ++{ ++ needsRedraw = (redraw_e)(needsRedraw | flags); ++ update(); ++} ++ ++void CCanvas::slotShowLoadIndicator() ++{ ++ QMutexLocker lock(&mutex); ++ mapLoadIndicator->show(); ++ mapLoadIndicatorCount++; ++} ++ ++void CCanvas::slotHideLoadIndicator() ++{ ++ QMutexLocker lock(&mutex); ++ if(--mapLoadIndicatorCount <= 0) ++ { ++ mapLoadIndicator->hide(); ++ mapLoadIndicatorCount = 0; ++ } ++} +diff --git a/src/qmaptool/canvas/CCanvas.h b/src/qmaptool/canvas/CCanvas.h +new file mode 100644 +index 00000000..552085ea +--- /dev/null ++++ b/src/qmaptool/canvas/CCanvas.h +@@ -0,0 +1,92 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CCANVAS_H ++#define CCANVAS_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++class ITool; ++class CMainWindow; ++class QStackedWidget; ++ ++class CCanvas : public QWidget ++{ ++ Q_OBJECT ++public: ++ CCanvas(QWidget *parent); ++ virtual ~CCanvas() = default; ++ ++ static void setOverrideCursor(const QCursor &cursor, const QString&); ++ static void restoreOverrideCursor(const QString &src); ++ static void changeOverrideCursor(const QCursor& cursor, const QString &src); ++ ++ enum redraw_e ++ { ++ eRedrawNone = 0 ++ , eRedrawMap = 0x01 ++ , eRedrawOverlay = 0x08 ++ , eRedrawAll = 0xFFFFFFFF ++ }; ++ ++ void setToolInterface(ITool * t) ++ { ++ tool = t; ++ } ++ ++signals: ++ void sigChangedSize(const QSize& size); ++ ++public slots: ++ void slotTriggerCompleteUpdate(CCanvas::redraw_e flags); ++ ++ void slotShowLoadIndicator(); ++ void slotHideLoadIndicator(); ++ ++protected: ++ void resizeEvent(QResizeEvent *e) override; ++ void paintEvent(QPaintEvent *e) override; ++ void mousePressEvent(QMouseEvent *e) override; ++ void mouseMoveEvent(QMouseEvent *e) override; ++ void mouseReleaseEvent(QMouseEvent *e) override; ++ void mouseDoubleClickEvent(QMouseEvent *e) override; ++ void wheelEvent(QWheelEvent *e) override; ++ void enterEvent(QEvent *e) override; ++ void leaveEvent(QEvent *e) override; ++ void keyPressEvent(QKeyEvent *e) override; ++ ++private: ++ mutable QMutex mutex {QMutex::Recursive}; ++ ++ QColor backColor = "#FFFFBF"; //< the background color used in case of missing map tiles ++ redraw_e needsRedraw = eRedrawAll; //< set true to initiate a complete redraw of the screen content ++ ++ /// load indicator for maps ++ QMovie * loadIndicator1; ++ QLabel * mapLoadIndicator; ++ qint32 mapLoadIndicatorCount = 0; ++ ++ ITool * tool = nullptr; ++}; ++ ++#endif //CCANVAS_H ++ +diff --git a/src/qmaptool/canvas/CDrawContextPixel.cpp b/src/qmaptool/canvas/CDrawContextPixel.cpp +new file mode 100644 +index 00000000..a28c383e +--- /dev/null ++++ b/src/qmaptool/canvas/CDrawContextPixel.cpp +@@ -0,0 +1,168 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "canvas/CDrawContextPixel.h" ++#include "helpers/CDraw.h" ++ ++#include ++#include ++#include ++ ++CDrawContextPixel::CDrawContextPixel(CCanvas *canvas, QObject * parent) ++ : IDrawContext(canvas, parent) ++{ ++ scale = QPointF(1.0, 1.0); ++} ++ ++CDrawContextPixel::~CDrawContextPixel() ++{ ++ unload(); ++} ++ ++void CDrawContextPixel::convertMap2Coord(QPointF &pt) const ++{ ++ pt = trFwd.map(pt); ++} ++ ++void CDrawContextPixel::convertCoord2Map(QPointF &pt) const ++{ ++ pt = trInv.map(pt); ++} ++ ++ ++void CDrawContextPixel::setSourceFile(const QString& filename, bool resetContext) ++{ ++ unload(); ++ ++ if(resetContext) ++ { ++ focus = QPointF(0,0); ++ zoom(6); ++ } ++ ++ if(filename.isEmpty()) ++ { ++ return; ++ } ++ ++ load(filename); ++ ++ intNeedsRedraw = true; ++} ++ ++void CDrawContextPixel::drawt(buffer_t& buf) ++{ ++ QPainter p(&buf.image); ++ ++ if(needsRedraw() || (dataset == nullptr) || (isValid == false)) ++ { ++ CDraw::text(tr("Failed to load"), p, canvas->rect(), Qt::black); ++ return; ++ } ++ ++ // calculate area to read from file ++ QPointF pt1 = buf.ref1; ++ QPointF pt2 = buf.ref2; ++ QPointF pt4 = buf.ref4; ++ ++ pt1.rx() = qMax(pt1.x(), 0.0); ++ pt1.rx() = qMin(pt1.x(), xsize_px); ++ ++ pt2.rx() = qMax(pt2.x(), 0.0); ++ pt2.rx() = qMin(pt2.x(), xsize_px); ++ ++ pt1.ry() = qMax(pt1.y(), 0.0); ++ pt1.ry() = qMin(pt1.y(), ysize_px); ++ ++ pt4.ry() = qMax(pt4.y(), 0.0); ++ pt4.ry() = qMin(pt4.y(), ysize_px); ++ ++ qint32 mapWidth = qRound(pt2.x() - pt1.x()); ++ qint32 mapHeight = qRound(pt4.y() - pt1.y()); ++ QPointF mapOff = pt1; ++ ++ convertMap2Screen(pt1); ++ convertMap2Screen(pt2); ++ convertMap2Screen(pt4); ++ ++ qint32 screenWidth = qRound(pt2.x() - pt1.x()) & 0xFFFFFFFC; ++ qint32 screenHeight = qRound(pt4.y() - pt1.y()); ++ QPointF screenOff = pt1; ++ ++ ++ // start to draw the map ++ QImage img; ++ QVector buffer(screenWidth * screenHeight, 0); ++ ++ CPLErr err = CE_Failure; ++ ++ if(rasterBandCount == 1) ++ { ++ GDALRasterBand * pBand; ++ pBand = dataset->GetRasterBand(1); ++ ++ img = QImage(screenWidth,screenHeight,QImage::Format_Indexed8); ++ img.setColorTable(colortable); ++ ++ mutex.lock(); ++ err = pBand->RasterIO(GF_Read, mapOff.x(), mapOff.y(), mapWidth, mapHeight, img.bits(), screenWidth, screenHeight, GDT_Byte, 0, 0); ++ mutex.unlock(); ++ } ++ else ++ { ++ const QRgb testPix = qRgba(GCI_RedBand, GCI_GreenBand, GCI_BlueBand, GCI_AlphaBand); ++ img = QImage(screenWidth, screenHeight, QImage::Format_ARGB32); ++ // fill alpha channel of image buffer ++ img.fill(Qt::white); ++ ++ // read map band by band and copy color values into the image buffer ++ for(int b = 1; b <= rasterBandCount; ++b) ++ { ++ GDALRasterBand * pBand; ++ pBand = dataset->GetRasterBand(b); ++ ++ mutex.lock(); ++ err = pBand->RasterIO(GF_Read, mapOff.x(), mapOff.y(), mapWidth, mapHeight, buffer.data(), screenWidth, screenHeight, GDT_Byte, 0, 0); ++ mutex.unlock(); ++ if(err == CE_None) ++ { ++ int pbandColour = pBand->GetColorInterpretation(); ++ unsigned int offset; ++ ++ for (offset = 0; offset < sizeof(testPix) && *(((quint8 *)&testPix) + offset) != pbandColour; offset++) ++ { ++ } ++ if(offset < sizeof(testPix)) ++ { ++ quint8 * pTar = img.bits() + offset; ++ quint8 * pSrc = buffer.data(); ++ const int size = buffer.size(); ++ ++ for(int i = 0; i < size; ++i) ++ { ++ *pTar = *pSrc; ++ pTar += sizeof(testPix); ++ pSrc += 1; ++ } ++ } ++ } ++ } ++ } ++ ++ p.drawImage(screenOff, img); ++} +diff --git a/src/qmaptool/canvas/CDrawContextPixel.h b/src/qmaptool/canvas/CDrawContextPixel.h +new file mode 100644 +index 00000000..7ebc598f +--- /dev/null ++++ b/src/qmaptool/canvas/CDrawContextPixel.h +@@ -0,0 +1,91 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CDRAWCONTEXTPIXEL_H ++#define CDRAWCONTEXTPIXEL_H ++ ++#include "canvas/IDrawContext.h" ++#include "helpers/CGdalFile.h" ++ ++class GDALDataset; ++ ++ ++class CDrawContextPixel : public IDrawContext, public CGdalFile ++{ ++ Q_OBJECT ++public: ++ CDrawContextPixel(CCanvas *canvas, QObject *parent); ++ virtual ~CDrawContextPixel(); ++ ++ void setSourceFile(const QString& filename, bool resetContext) override; ++ ++ void unload() override ++ { ++ CGdalFile::unload(); ++ } ++ ++ bool getIsValid() const override ++ { ++ return isValid; ++ } ++ ++ const QString& getProjection() const override ++ { ++ return proj4str; ++ } ++ ++ const QTransform& getTrFwd() const override ++ { ++ return trFwd; ++ } ++ ++ bool getNoData() const override ++ { ++ return hasNoData != -1; ++ } ++ ++ int getRasterBandCount() const override ++ { ++ return rasterBandCount; ++ } ++ ++ QString getInfo() const override ++ { ++ return CGdalFile::getInfo(); ++ } ++ ++ bool is32BitRgb() const override ++ { ++ return rasterBandCount >= 3; ++ } ++ ++ ++ QRectF getMapArea() const override ++ { ++ return QRectF(0,0, xsize_px, ysize_px); ++ } ++ ++ void convertMap2Coord(QPointF &pt) const override; ++ void convertCoord2Map(QPointF &pt) const override; ++ ++protected: ++ void drawt(buffer_t& buf) override; ++}; ++ ++#endif //CDRAWCONTEXTPIXEL_H ++ +diff --git a/src/qmaptool/canvas/CDrawContextProj.cpp b/src/qmaptool/canvas/CDrawContextProj.cpp +new file mode 100644 +index 00000000..c2ac302a +--- /dev/null ++++ b/src/qmaptool/canvas/CDrawContextProj.cpp +@@ -0,0 +1,166 @@ ++/********************************************************************************************** ++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "canvas/CDrawContextProj.h" ++#include "helpers/CDraw.h" ++ ++#include ++#include ++ ++CDrawContextProj::CDrawContextProj(CCanvas *canvas, QObject *parent) ++ : IDrawContext(canvas, parent) ++{ ++} ++ ++void CDrawContextProj::setSourceFile(const QString& filename, bool resetContext) ++{ ++ unload(); ++ ++ if(resetContext) ++ { ++ focus = QPointF(0,0); ++ zoom(6); ++ } ++ ++ if(filename.isEmpty()) ++ { ++ return; ++ } ++ ++ load(filename); ++ ++ if(resetContext) ++ { ++ convertMap2Coord(focus); ++ } ++ ++ intNeedsRedraw = true; ++} ++ ++void CDrawContextProj::convertMap2Coord(QPointF &pt) const ++{ ++ pt = trFwd.map(pt); ++} ++ ++void CDrawContextProj::convertCoord2Map(QPointF &pt) const ++{ ++ pt = trInv.map(pt); ++} ++ ++ ++void CDrawContextProj::drawt(buffer_t& buf) ++{ ++ QPainter p(&buf.image); ++ ++ if(needsRedraw() || (dataset == nullptr) || (isValid == false)) ++ { ++ CDraw::text(tr("Failed to load"), p, canvas->rect(), Qt::black); ++ return; ++ } ++ ++ // calculate area to read from file ++ QPointF pt1 = buf.ref1; ++ QPointF pt3 = buf.ref3; ++ ++ pt1.rx() = qMax(CGdalFile::ref1.x(), pt1.x()); ++ pt1.rx() = qMin(CGdalFile::ref2.x(), pt1.x()); ++ ++ pt1.ry() = qMin(CGdalFile::ref1.y(), pt1.y()); ++ pt1.ry() = qMax(CGdalFile::ref3.y(), pt1.y()); ++ ++ pt3.rx() = qMax(CGdalFile::ref1.x(), pt3.x()); ++ pt3.rx() = qMin(CGdalFile::ref2.x(), pt3.x()); ++ ++ pt3.ry() = qMin(CGdalFile::ref1.y(), pt3.y()); ++ pt3.ry() = qMax(CGdalFile::ref3.y(), pt3.y()); ++ ++ convertCoord2Map(pt1); ++ convertCoord2Map(pt3); ++ ++ qint32 mapWidth = qRound(pt3.x() - pt1.x()); ++ qint32 mapHeight = qRound(pt3.y() - pt1.y()); ++ QPointF mapOff = pt1; ++ ++ convertMap2Screen(pt1); ++ convertMap2Screen(pt3); ++ ++ qint32 screenWidth = qRound(pt3.x() - pt1.x()) & 0xFFFFFFFC; ++ qint32 screenHeight = qRound(pt3.y() - pt1.y()); ++ QPointF screenOff = pt1; ++ ++ // start to draw the map ++ QImage img; ++ QVector buffer(screenWidth * screenHeight, 0); ++ ++ CPLErr err = CE_Failure; ++ ++ if(rasterBandCount == 1) ++ { ++ GDALRasterBand * pBand; ++ pBand = dataset->GetRasterBand(1); ++ ++ img = QImage(screenWidth,screenHeight,QImage::Format_Indexed8); ++ img.setColorTable(colortable); ++ ++ mutex.lock(); ++ err = pBand->RasterIO(GF_Read, mapOff.x(), mapOff.y(), mapWidth, mapHeight, img.bits(), screenWidth, screenHeight, GDT_Byte, 0, 0); ++ mutex.unlock(); ++ } ++ else ++ { ++ const QRgb testPix = qRgba(GCI_RedBand, GCI_GreenBand, GCI_BlueBand, GCI_AlphaBand); ++ img = QImage(screenWidth, screenHeight, QImage::Format_ARGB32); ++ // fill alpha channel of image buffer ++ img.fill(Qt::white); ++ ++ // read map band by band and copy color values into the image buffer ++ for(int b = 1; b <= rasterBandCount; ++b) ++ { ++ GDALRasterBand * pBand; ++ pBand = dataset->GetRasterBand(b); ++ ++ mutex.lock(); ++ err = pBand->RasterIO(GF_Read, mapOff.x(), mapOff.y(), mapWidth, mapHeight, buffer.data(), screenWidth, screenHeight, GDT_Byte, 0, 0); ++ mutex.unlock(); ++ if(err == CE_None) ++ { ++ int pbandColour = pBand->GetColorInterpretation(); ++ unsigned int offset; ++ ++ for (offset = 0; offset < sizeof(testPix) && *(((quint8 *)&testPix) + offset) != pbandColour; offset++) ++ { ++ } ++ if(offset < sizeof(testPix)) ++ { ++ quint8 * pTar = img.bits() + offset; ++ quint8 * pSrc = buffer.data(); ++ const int size = buffer.size(); ++ ++ for(int i = 0; i < size; ++i) ++ { ++ *pTar = *pSrc; ++ pTar += sizeof(testPix); ++ pSrc += 1; ++ } ++ } ++ } ++ } ++ } ++ ++ p.drawImage(screenOff, img); ++} +diff --git a/src/qmaptool/canvas/CDrawContextProj.h b/src/qmaptool/canvas/CDrawContextProj.h +new file mode 100644 +index 00000000..ecb10f92 +--- /dev/null ++++ b/src/qmaptool/canvas/CDrawContextProj.h +@@ -0,0 +1,89 @@ ++/********************************************************************************************** ++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CDRAWCONTEXTPROJ_H ++#define CDRAWCONTEXTPROJ_H ++ ++#include "canvas/IDrawContext.h" ++#include "helpers/CGdalFile.h" ++ ++#include ++ ++class CDrawContextProj : public IDrawContext, public CGdalFile ++{ ++ Q_OBJECT ++public: ++ CDrawContextProj(CCanvas *canvas, QObject *parent); ++ virtual ~CDrawContextProj() = default; ++ ++ void setSourceFile(const QString& filename, bool resetContext) override; ++ ++ void unload() override ++ { ++ CGdalFile::unload(); ++ } ++ ++ bool getIsValid() const override ++ { ++ return isValid; ++ } ++ ++ const QString& getProjection() const override ++ { ++ return proj4str; ++ } ++ ++ const QTransform& getTrFwd() const override ++ { ++ return trFwd; ++ } ++ ++ bool getNoData() const override ++ { ++ return hasNoData != -1; ++ } ++ ++ int getRasterBandCount() const override ++ { ++ return rasterBandCount; ++ } ++ ++ QString getInfo() const override ++ { ++ return CGdalFile::getInfo(); ++ } ++ ++ bool is32BitRgb() const override ++ { ++ return rasterBandCount >= 3; ++ } ++ ++ ++ QRectF getMapArea() const override ++ { ++ return QRectF(0,0, xsize_px, ysize_px); ++ } ++ ++ void convertMap2Coord(QPointF &pt) const override; ++ void convertCoord2Map(QPointF &pt) const override; ++ ++ void drawt(buffer_t& buf) override; ++}; ++ ++#endif //CDRAWCONTEXTPROJ_H ++ +diff --git a/src/qmaptool/canvas/IDrawContext.cpp b/src/qmaptool/canvas/IDrawContext.cpp +new file mode 100644 +index 00000000..ce960e24 +--- /dev/null ++++ b/src/qmaptool/canvas/IDrawContext.cpp +@@ -0,0 +1,300 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "canvas/IDrawContext.h" ++ ++#include ++ ++#define N_DEFAULT_ZOOM_LEVELS 31 ++const qreal IDrawContext::scales[N_DEFAULT_ZOOM_LEVELS] = ++{ ++ 0.10, 0.15, 0.20, 0.30, 0.50, 0.70, 1.0, 1.5, 2.0, 3.0, ++ 5.0, 7.0, 10.0, 15.0, 20.0, 30.0, 50.0, 70.0, 100.0, 150.0, ++ 200.0, 300.0, 500.0, 700.0, 1000.0, 1500.0, 2000.0, 3000.0, 5000.0, 7000.0, ++ 10000.0 ++ //, 15000.0, 20000.0, 30000.0, 50000.0, 70000.0 ++}; ++ ++QPointF operator*(const QPointF& p1, const QPointF& p2) ++{ ++ return QPointF(p1.x() * p2.x(), p1.y() * p2.y()); ++} ++ ++QPointF operator/(const QPointF& p1, const QPointF& p2) ++{ ++ return QPointF(p1.x() / p2.x(), p1.y() / p2.y()); ++} ++ ++QMutex IDrawContext::mutex(QMutex::Recursive); ++ ++ ++IDrawContext::IDrawContext(CCanvas * canvas, QObject * parent) ++ : QThread(parent) ++ , canvas(canvas) ++{ ++ init(); ++} ++ ++void IDrawContext::init() ++{ ++ connect(this, &IDrawContext::finished, canvas, static_cast(&CCanvas::update)); ++ connect(this, &IDrawContext::started, canvas, &CCanvas::slotShowLoadIndicator); ++ connect(this, &IDrawContext::finished, canvas, &CCanvas::slotHideLoadIndicator); ++ connect(canvas, &CCanvas::sigChangedSize, this, &IDrawContext::slotResize); ++ ++ slotResize(canvas->size()); ++} ++ ++ ++void IDrawContext::saveSettings(QSettings& cfg) const ++{ ++ QMutexLocker lock(&mutex); ++ ++ cfg.beginGroup("DrawContext"); ++ cfg.setValue("focus", focus); ++ cfg.setValue("zoomFactorIdx", zoomFactorIdx); ++ cfg.endGroup(); ++} ++ ++void IDrawContext::loadSettings(QSettings& cfg) ++{ ++ QMutexLocker lock(&mutex); ++ ++ cfg.beginGroup("DrawContext"); ++ focus = cfg.value("focus", focus).toPointF(); ++ zoomFactorIdx = cfg.value("zoomFactorIdx", zoomFactorIdx).toInt(); ++ cfg.endGroup(); ++ ++ zoom(zoomFactorIdx); ++} ++ ++ ++void IDrawContext::slotResize(const QSize& size) ++{ ++ if(isRunning()) ++ { ++ wait(); ++ } ++ ++ QMutexLocker lock(&mutex); ++ viewWidth = size.width(); ++ viewHeight = size.height(); ++ ++ bufWidth = viewWidth; ++ bufHeight = viewHeight; ++ ++ buffer[0].image = QImage(qRound(bufWidth), qRound(bufHeight), QImage::Format_ARGB32); ++ buffer[1].image = QImage(qRound(bufWidth), qRound(bufHeight), QImage::Format_ARGB32); ++} ++ ++bool IDrawContext::needsRedraw() const ++{ ++ mutex.lock(); // --------- start serialize with thread ++ bool res = intNeedsRedraw; ++ mutex.unlock(); // --------- stop serialize with thread ++ return res; ++} ++ ++void IDrawContext::convertScreen2Map(QPointF& pt) const ++{ ++ mutex.lock(); // --------- start serialize with thread ++ ++ QPointF f = focus; ++ convertCoord2Map(f); ++ ++ pt = f + pt * scale * zoomFactor; ++ ++ mutex.unlock(); // --------- stop serialize with thread ++} ++ ++void IDrawContext::convertMap2Screen(QPointF& pt) const ++{ ++ mutex.lock(); // --------- start serialize with thread ++ ++ QPointF f = focus; ++ convertCoord2Map(f); ++ ++ pt = (pt - f) / (scale * zoomFactor); ++ ++ mutex.unlock(); // --------- stop serialize with thread ++} ++ ++void IDrawContext::convertMap2Screen(QPolygonF& line) const ++{ ++ mutex.lock(); // --------- start serialize with thread ++ ++ const int N = line.size(); ++ for(int n = 0; n < N; n++) ++ { ++ line[n] = (line[n] - focus) / (scale * zoomFactor); ++ } ++ ++ mutex.unlock(); // --------- stop serialize with thread ++} ++ ++void IDrawContext::convertMap2Screen(QRectF& rect) const ++{ ++ mutex.lock(); // --------- start serialize with thread ++ ++ QPointF topLeft = rect.topLeft(); ++ convertMap2Screen(topLeft); ++ rect.setTopLeft(topLeft); ++ ++ QPointF bottomRight = rect.bottomRight(); ++ convertMap2Screen(bottomRight); ++ rect.setBottomRight(bottomRight); ++ ++ mutex.unlock(); // --------- stop serialize with thread ++} ++ ++ ++void IDrawContext::move(const QPointF& delta) ++{ ++ mutex.lock(); // --------- start serialize with thread ++ QPointF f = focus; ++ ++ convertCoord2Map(f); ++ convertMap2Screen(f); ++ f -= delta; ++ convertScreen2Map(f); ++ convertMap2Coord(f); ++ ++ focus = f; ++ mutex.unlock(); // --------- stop serialize with thread ++} ++ ++void IDrawContext::zoom(bool in, const QPointF& pt) ++{ ++ mutex.lock(); // --------- start serialize with thread ++ ++ QPointF pt2 = pt; ++ ++ convertScreen2Map(pt2); ++ zoom(zoomFactorIdx + (in ? -1 : 1)); ++ convertMap2Screen(pt2); ++ ++ move(pt - pt2); ++ ++ mutex.unlock(); // --------- stop serialize with thread ++} ++ ++void IDrawContext::zoom(int idx) ++{ ++ idx = qMax(idx, 0); ++ idx = qMin(idx, N_DEFAULT_ZOOM_LEVELS - 1); ++ ++ mutex.lock(); // --------- start serialize with thread ++ if((zoomFactorIdx != idx) || (zoomFactor.x() != scales[idx])) ++ { ++ zoomFactorIdx = idx; ++ zoomFactor.rx() = scales[idx]; ++ zoomFactor.ry() = scales[idx]; ++ intNeedsRedraw = true; ++ } ++ mutex.unlock(); // --------- stop serialize with thread ++} ++ ++void IDrawContext::draw(QPainter& p, CCanvas::redraw_e needsRedraw) ++{ ++ mutex.lock(); // --------- start serialize with thread ++ // derive map reference points for all corners coordinate of map buffer ++ ref1 = QPointF( 0, 0); ++ ref2 = QPointF( bufWidth, 0); ++ ref3 = QPointF( bufWidth, bufHeight); ++ ref4 = QPointF( 0, bufHeight); ++ ++ convertScreen2Map(ref1); ++ convertScreen2Map(ref2); ++ convertScreen2Map(ref3); ++ convertScreen2Map(ref4); ++ ++ convertMap2Coord(ref1); ++ convertMap2Coord(ref2); ++ convertMap2Coord(ref3); ++ convertMap2Coord(ref4); ++ ++ // get current active buffer ++ const buffer_t& currentBuffer = buffer[bufIndex]; ++ ++ // calculate screen offset of current buffer ++ QPointF offset = currentBuffer.ref1; ++ convertCoord2Map(offset); ++ convertMap2Screen(offset); ++ ++ p.save(); ++ // add offset ++ p.translate(offset); ++ // scale image if current zoomfactor does not match buffer's zoomfactor ++ p.scale(currentBuffer.zoomFactor.x()/zoomFactor.x(), currentBuffer.zoomFactor.y()/zoomFactor.y()); ++ // draw buffer to painter ++ p.drawImage(0,0, currentBuffer.image); ++ p.restore(); ++ ++ emit sigDraw(p); ++ ++ // intNeedsRedraw is reset by the thread ++ if(needsRedraw & maskRedraw) ++ { ++ intNeedsRedraw = true; ++ } ++ mutex.unlock(); // --------- stop serialize with thread ++ ++ if((needsRedraw & maskRedraw) && !isRunning()) ++ { ++ start(); ++ } ++} ++ ++ ++void IDrawContext::run() ++{ ++ mutex.lock(); ++ ++ QTime t; ++ t.start(); ++ qDebug() << "start thread" << objectName(); ++ ++ IDrawContext::buffer_t& currentBuffer = buffer[!bufIndex]; ++ while(intNeedsRedraw) ++ { ++ // copy all projection information need by the ++ // map render objects to buffer structure ++ currentBuffer.zoomFactor = zoomFactor; ++ currentBuffer.scale = scale; ++ currentBuffer.ref1 = ref1; ++ currentBuffer.ref2 = ref2; ++ currentBuffer.ref3 = ref3; ++ currentBuffer.ref4 = ref4; ++ currentBuffer.focus = focus; ++ intNeedsRedraw = false; ++ ++ mutex.unlock(); ++ // ----- reset buffer ----- ++ currentBuffer.image.fill(Qt::transparent); ++ ++ drawt(currentBuffer); ++ ++ mutex.lock(); ++ } ++ // ----- switch buffer ------ ++ bufIndex = !bufIndex; ++ qDebug() << "stop thread" << objectName() << "after" << t.elapsed() << "ms"; ++ ++ mutex.unlock(); ++} ++ +diff --git a/src/qmaptool/canvas/IDrawContext.h b/src/qmaptool/canvas/IDrawContext.h +new file mode 100644 +index 00000000..c87d4403 +--- /dev/null ++++ b/src/qmaptool/canvas/IDrawContext.h +@@ -0,0 +1,164 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef IDRAWCONTEXT_H ++#define IDRAWCONTEXT_H ++ ++#include "canvas/CCanvas.h" ++#include "units/IUnit.h" ++ ++#include ++#include ++class QPainter; ++class QSettings; ++ ++class IDrawContext : public QThread ++{ ++ Q_OBJECT ++public: ++ IDrawContext(CCanvas *canvas, QObject *parent); ++ virtual ~IDrawContext() = default; ++ ++ virtual QString getInfo() const = 0; ++ ++ virtual bool is32BitRgb() const = 0; ++ ++ virtual int getRasterBandCount() const = 0; ++ ++ virtual bool getNoData() const = 0; ++ ++ virtual const QString& getProjection() const = 0; ++ ++ virtual const QTransform& getTrFwd() const = 0; ++ ++ virtual QRectF getMapArea() const = 0; ++ ++ virtual void setSourceFile(const QString& filename, bool resetContext) = 0; ++ ++ virtual void unload() = 0; ++ ++ virtual bool getIsValid() const = 0; ++ ++ virtual void saveSettings(QSettings& cfg) const; ++ ++ virtual void loadSettings(QSettings& cfg); ++ ++ void move(const QPointF& delta); ++ ++ void zoom(bool in, const QPointF& pt); ++ ++ bool needsRedraw() const; ++ ++ void convertScreen2Map(QPointF &pt) const; ++ void convertMap2Screen(QPointF& pt) const; ++ void convertMap2Screen(QPolygonF& line) const; ++ void convertMap2Screen(QRectF &rect) const; ++ ++ virtual void convertMap2Coord(QPointF &pt) const = 0; ++ virtual void convertCoord2Map(QPointF &pt) const = 0; ++ ++ /** ++ @brief draw ++ @param p ++ @param needsRedraw ++ */ ++ void draw(QPainter& p, CCanvas::redraw_e needsRedraw); ++ ++ void triggerCompleteUpdate(CCanvas::redraw_e flags) const ++ { ++ canvas->slotTriggerCompleteUpdate(flags); ++ } ++ ++ const CCanvas * getCanvas() const ++ { ++ return canvas; ++ } ++ ++signals: ++ void sigDraw(QPainter& p); ++ ++protected slots: ++ void slotResize(const QSize& size); ++ ++protected: ++ CCanvas *canvas; ++ ++ struct buffer_t ++ { ++ QImage image; ++ ++ QPointF zoomFactor {1.0,1.0}; //< the zoomfactor used to draw the canvas ++ QPointF scale {1.0,1.0}; //< the scale of the global viewport ++ ++ QPointF ref1; //< top left corner ++ QPointF ref2; //< top right corner ++ QPointF ref3; //< bottom right corner ++ QPointF ref4; //< bottom left corner ++ QPointF focus; //< point of focus ++ }; ++ ++ void run() override; ++ ++ virtual void drawt(buffer_t& currentBuffer) = 0; ++ ++ void zoom(int idx); ++ ++ static QMutex mutex; ++ ++ /// internal needs redraw flag ++ bool intNeedsRedraw = true; ++ ++ const CCanvas::redraw_e maskRedraw = CCanvas::eRedrawMap; ++ ++ /// map canvas twin buffer ++ buffer_t buffer[2]; ++ /// the main threads currently used map canvas buffer ++ bool bufIndex = false; ++ ++ qreal bufWidth = 100; //< buffer width [px] ++ qreal bufHeight = 100; //< buffer height [px] ++ qreal viewWidth = 100; //< the viewports width [px] ++ qreal viewHeight = 100; //< the viewports height [px] ++ ++ QPointF focus {0, 0}; ++ ++ /// the basic scale of the map canvas ++ QPointF scale = QPoint(1.0, 1.0); ++ ++private: ++ void init(); ++ ++ static const qreal scales[]; ++ qint32 zoomFactorIdx = 6; ++ ++ /// the actual used scaleFactor ++ QPointF zoomFactor {scales[zoomFactorIdx], scales[zoomFactorIdx]}; ++ ++ QPointF ref1; //< top left corner of next buffer ++ QPointF ref2; //< top right corner of next buffer ++ QPointF ref3; //< bottom right corner of next buffer ++ QPointF ref4; //< bottom left corner of next buffer ++}; ++ ++extern QPointF operator*(const QPointF& p1, const QPointF& p2); ++ ++extern QPointF operator/(const QPointF& p1, const QPointF& p2); ++ ++ ++#endif //IDRAWCONTEXT_H ++ +diff --git a/src/qmaptool/helpers/CDraw.cpp b/src/qmaptool/helpers/CDraw.cpp +new file mode 100644 +index 00000000..ef2367d7 +--- /dev/null ++++ b/src/qmaptool/helpers/CDraw.cpp +@@ -0,0 +1,239 @@ ++/********************************************************************************************** ++ Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de ++ Copyright (C) 2015 Christian Eichler code@christian-eichler.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "canvas/CCanvas.h" ++#include "helpers/CDraw.h" ++ ++#include ++#include ++#include ++#include ++ ++QPen CDraw::penBorderBlue(QColor(10,10,150,220),2); ++QPen CDraw::penBorderGray(Qt::lightGray,2); ++QPen CDraw::penBorderBlack(QColor(0,0,0,200),2); ++QBrush CDraw::brushBackWhite(QColor(255,255,255,255)); ++QBrush CDraw::brushBackYellow(QColor(0xff, 0xff, 0xcc, 0xE0)); ++ ++ ++QImage CDraw::createBasicArrow(const QBrush &brush, qreal scale) ++{ ++ QImage arrow(21*scale, 16*scale, QImage::Format_ARGB32); ++ arrow.fill(qRgba(0, 0, 0, 0)); ++ ++ QPainter painter(&arrow); ++ USE_ANTI_ALIASING(painter, true); ++ ++ // white background, same foreground as p ++ painter.setPen(QPen(Qt::white, 2)); ++ painter.setBrush(brush); ++ ++ QPointF arrowPoints[4] = ++ { ++ QPointF(20.0*scale, 7.0*scale), // front ++ QPointF( 0.0*scale, 0.0*scale), // upper tail ++ QPointF( 5.0*scale, 7.0*scale), // mid tail ++ QPointF( 0.0*scale, 15.0*scale) // lower tail ++ }; ++ painter.drawPolygon(arrowPoints, 4); ++ painter.end(); ++ ++ return arrow; ++} ++ ++/** ++ @brief Calculates the square distance between two points ++ @return (int) ( (x2 - x1)^2 + (y2 - y1)^2 ) ++ */ ++ ++static inline int pointDistanceSquare(const QPointF &p1, const QPointF &p2) ++{ ++ return (p2.x() - p1.x()) * (p2.x() - p1.x()) + (p2.y() - p1.y()) * (p2.y() - p1.y()); ++} ++ ++void CDraw::arrows(const QPolygonF &line, const QRectF &viewport, QPainter &p, int minPointDist, int minArrowDist, qreal scale) ++{ ++ QImage arrow = createBasicArrow(p.brush(), scale); ++ qreal xoff = qCeil(arrow.width()/2.0); ++ qreal yoff = qFloor((arrow.height()-1)/2.0); ++ ++ const qreal minArrowDistSquare = minArrowDist * minArrowDist; ++ const qreal minPointDistSquare = minPointDist * minPointDist; ++ ++ QPointF prevArrow; ++ bool firstArrow = true; ++ for(int i = 1; i < line.size(); i++) ++ { ++ const QPointF &pt = line[i ]; ++ const QPointF &prevPt = line[i - 1]; ++ ++ // ensure there is enough space between two line points ++ if( pointDistanceSquare(pt, prevPt) >= minPointDistSquare ) ++ { ++ QPointF arrowPos = prevPt + (pt - prevPt)/2; ++ ++ if( (viewport.contains(pt) || 0 == viewport.height()) // ensure the point is visible ++ && (firstArrow || pointDistanceSquare(prevArrow, arrowPos) >= minArrowDistSquare) ) ++ { ++ p.save(); ++ ++ // rotate and draw the arrow (between bullets) ++ p.translate(arrowPos); ++ qreal direction = ( qAtan2((pt.y() - prevPt.y()), (pt.x() - prevPt.x())) * 180.) / M_PI; ++ p.rotate(direction); ++ p.drawImage(-xoff, -yoff, arrow); ++ ++ p.restore(); ++ ++ prevArrow = arrowPos; ++ firstArrow = false; ++ } ++ } ++ } ++} ++ ++void CDraw::text(const QString &str, QPainter &p, const QPoint ¢er, const QColor &color, const QFont &font) ++{ ++ QFontMetrics fm(font); ++ QRect r = fm.boundingRect(str); ++ ++ r.moveCenter(center); ++ p.setFont(font); ++ ++ // draw the white `shadow` ++ p.setPen(Qt::white); ++ p.drawText(r.topLeft() - QPoint(-1, -1), str); ++ p.drawText(r.topLeft() - QPoint( 0, -1), str); ++ p.drawText(r.topLeft() - QPoint(+1, -1), str); ++ ++ p.drawText(r.topLeft() - QPoint(-1, 0), str); ++ p.drawText(r.topLeft() - QPoint(+1, 0), str); ++ ++ p.drawText(r.topLeft() - QPoint(-1, +1), str); ++ p.drawText(r.topLeft() - QPoint( 0, +1), str); ++ p.drawText(r.topLeft() - QPoint(+1, +1), str); ++ ++ p.setPen(color); ++ p.drawText(r.topLeft(), str); ++} ++ ++void CDraw::text(const QString &str, QPainter &p, const QRect &r, const QColor &color) ++{ ++ p.setPen(Qt::white); ++ p.setFont(CMainWindow::self().getMapFont()); ++ ++ // draw the white `shadow` ++ p.drawText(r.adjusted(-1, -1, -1, -1), Qt::AlignCenter, str); ++ p.drawText(r.adjusted( 0, -1, 0, -1), Qt::AlignCenter, str); ++ p.drawText(r.adjusted(+1, -1, +1, -1), Qt::AlignCenter, str); ++ ++ p.drawText(r.adjusted(-1, 0, -1, 0), Qt::AlignCenter, str); ++ p.drawText(r.adjusted(+1, 0, +1, 0), Qt::AlignCenter, str); ++ ++ p.drawText(r.adjusted(-1, +1, -1, +1), Qt::AlignCenter, str); ++ p.drawText(r.adjusted( 0, +1, 0, +1), Qt::AlignCenter, str); ++ p.drawText(r.adjusted(+1, +1, +1, +1), Qt::AlignCenter, str); ++ ++ p.setPen(color); ++ p.drawText(r, Qt::AlignCenter, str); ++} ++ ++QPoint CDraw::bubble(QPainter &p, const QRect &contentRect, const QPoint &pointerPos, int pointerBaseWidth, float pointerBasePos) ++{ ++ QPainterPath bubblePath; ++ bubblePath.addRoundedRect(contentRect, RECT_RADIUS, RECT_RADIUS); ++ ++ // draw the arrow ++ int pointerBaseCenterX = (pointerBasePos <= 1) ++ ? contentRect.left() + (pointerBasePos * contentRect.width()) ++ : contentRect.left() + (int) pointerBasePos; ++ ++ int pointerHeight = 0; ++ if(pointerPos.y() < contentRect.top()) ++ { ++ pointerHeight = contentRect.top() - pointerPos.y() + 1; ++ } ++ else if(pointerPos.y() > contentRect.bottom()) ++ { ++ pointerHeight = contentRect.bottom() - pointerPos.y() - 1; ++ } ++ else ++ { ++ qDebug() << "cannot calculate pointerHeight/pointerBaseCenterX due to invalid parameters"; ++ } ++ ++ if(0 != pointerHeight) ++ { ++ QPolygonF pointerPoly; ++ pointerPoly << pointerPos ++ << QPointF(pointerBaseCenterX - pointerBaseWidth / 2, pointerPos.y() + pointerHeight) ++ << QPointF(pointerBaseCenterX + pointerBaseWidth / 2, pointerPos.y() + pointerHeight) ++ << pointerPos; ++ ++ QPainterPath pointerPath; ++ pointerPath.addPolygon(pointerPoly); ++ ++ bubblePath = bubblePath.united(pointerPath); ++ } ++ ++ p.setPen (CDraw::penBorderGray); ++ p.setBrush(CDraw::brushBackWhite); ++ ++ p.drawPolygon(bubblePath.toFillPolygon()); ++ ++ return contentRect.topLeft(); ++} ++ ++void CDraw::drawCrossHairDot(QPainter& p, const QPointF& pt) ++{ ++ USE_ANTI_ALIASING(p, false); ++ p.setBrush(Qt::NoBrush); ++ QRectF dot2(0,0,7,7); ++ p.setPen(QPen(Qt::white, 3)); ++ p.drawLine(pt.x(), pt.y() + 3, pt.x(), pt.y() + 20); ++ p.drawLine(pt.x(), pt.y() - 3, pt.x(), pt.y() - 20); ++ p.drawLine(pt.x() - 3, pt.y(), pt.x() - +20, pt.y()); ++ p.drawLine(pt.x() + 3, pt.y(), pt.x() + 20, pt.y()); ++ p.setPen(QPen(Qt::red, 1)); ++ p.drawLine(pt.x(), pt.y() + 3, pt.x(), pt.y() + 20); ++ p.drawLine(pt.x(), pt.y() - 3, pt.x(), pt.y() - 20); ++ p.drawLine(pt.x() - 3, pt.y(), pt.x() - +20, pt.y()); ++ p.drawLine(pt.x() + 3, pt.y(), pt.x() + 20, pt.y()); ++ ++ dot2.moveCenter(pt); ++ p.setPen(QPen(Qt::white, 3)); ++ p.drawRect(dot2); ++ p.setPen(QPen(Qt::red, 1)); ++ p.drawRect(dot2); ++ USE_ANTI_ALIASING(p, true); ++} ++ ++void CDraw::drawRectangle(QPainter& p, const QRectF& rect, const QPen& pen, const QBrush& brush) ++{ ++ p.setBrush(brush); ++ p.setPen(QPen(Qt::white, pen.width() + 2)); ++ p.drawRect(rect); ++ p.setPen(pen); ++ p.drawRect(rect); ++} ++ ++void CDraw::drawRectangle(QPainter& p, const QRectF& rect, const Qt::GlobalColor& pen, const Qt::GlobalColor& brush) ++{ ++ drawRectangle(p,rect, QPen(pen), QBrush(brush)); ++} +diff --git a/src/qmaptool/helpers/CDraw.h b/src/qmaptool/helpers/CDraw.h +new file mode 100644 +index 00000000..517d6baf +--- /dev/null ++++ b/src/qmaptool/helpers/CDraw.h +@@ -0,0 +1,96 @@ ++/********************************************************************************************** ++ Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de ++ Copyright (C) 2015 Christian Eichler code@christian-eichler.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CPAINTER_H ++#define CPAINTER_H ++ ++#include ++#include ++#include ++ ++#include "CMainWindow.h" ++inline void USE_ANTI_ALIASING(QPainter& p, bool useAntiAliasing) ++{ ++ p.setRenderHints(QPainter::TextAntialiasing|QPainter::Antialiasing|QPainter::SmoothPixmapTransform|QPainter::HighQualityAntialiasing, useAntiAliasing); ++} ++ ++#define RECT_RADIUS 3 ++#define PAINT_ROUNDED_RECT(p,r) p.drawRoundedRect(r,RECT_RADIUS,RECT_RADIUS) ++ ++ ++class CDraw ++{ ++public: ++ ++ static QPen penBorderBlue; ++ static QPen penBorderGray; ++ static QPen penBorderBlack; ++ static QBrush brushBackWhite; ++ static QBrush brushBackYellow; ++ ++ /** ++ @brief Draw arrows along a line ++ ++ An arrow is drawn if all the following requirements are met: ++ * the position the new arrow would have been drawn is within viewport ++ OR ++ `viewport.height() == 0` ++ * the two points have a distance of at least `minPointDist` ++ * the (potential) position of the new arrow has at least a distance of `minArrowDist` from the previous arrow ++ ++ @param line The line to draw the arrows along ++ @param viewport Restrict drawing of arrows to this viewport (no limitation is applied if `viewport.height() == 0`) ++ @param minPointDist The minimum distance of two points (in px) ++ @param minArrowDist The minimum distance of two consecutive arrows (in px) ++ */ ++ static void arrows(const QPolygonF &line, const QRectF &viewport, QPainter &p, int minPointDist, int minArrowDist, qreal scale); ++ ++ static void text(const QString& str, QPainter &p, const QPoint ¢er, const QColor &color, const QFont &font = CMainWindow::self().getMapFont()); ++ static void text(const QString& str, QPainter &p, const QRect &r, const QColor &color); ++ ++ /** ++ @brief Draw a cartoon bubble ++ ++ `pointerBasePos` denotes the position of the pointer's base, where 0 is `at the very left of the content`, and 1 is `at the very right`. ++ Be careful with small values (near 0) or large values (near 1) for pointerBasePos, this might lead to incorrect drawing, ++ especially if pointerBaseWidth is large. ++ If is larger than 1, a value in pixels is assumed. ++ ++ @param p An active QPainter ++ @param contentRect The area the actual content will be in ++ @param pointerPos The position of the pointer's head ++ @param pointerBaseWidth The width of the pointer ++ @param pointerBasePos The (relative) location of the pointer (in percent / pixels) ++ */ ++ static QPoint bubble(QPainter &p, const QRect &contentRect, const QPoint &pointerPos, int pointerBaseWidth = 20, float pointerBasePos = .5f); ++ ++ static void drawCrossHairDot(QPainter& p, const QPointF& pt); ++ ++ static void drawRectangle(QPainter& p, const QRectF& rect, const Qt::GlobalColor& pen, const Qt::GlobalColor& brush); ++ static void drawRectangle(QPainter& p, const QRectF& rect, const QPen& pen, const QBrush& brush); ++private: ++ /** ++ @brief Creates a new arrow using the brush specified ++ @return A QImage containing the arrow ++ */ ++ static QImage createBasicArrow(const QBrush &brush, qreal scale); ++}; ++ ++#endif // CPAINTER_H ++ +diff --git a/src/qmaptool/helpers/CGdalFile.cpp b/src/qmaptool/helpers/CGdalFile.cpp +new file mode 100644 +index 00000000..f1d875ec +--- /dev/null ++++ b/src/qmaptool/helpers/CGdalFile.cpp +@@ -0,0 +1,221 @@ ++/********************************************************************************************** ++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "canvas/CCanvas.h" ++#include "CMainWindow.h" ++#include "helpers/CGdalFile.h" ++ ++#include ++#include ++ ++#include ++ ++CGdalFile::CGdalFile() ++{ ++} ++ ++ ++void CGdalFile::unload() ++{ ++ isValid = false; ++ if(dataset != nullptr) ++ { ++ GDALClose(dataset); ++ } ++ dataset = nullptr; ++} ++ ++ ++void CGdalFile::load(const QString& filename) ++{ ++ qDebug() << filename; ++ CCanvas * canvas = CMainWindow::self().getCanvas(); ++ ++ dataset = (GDALDataset*)GDALOpenShared(filename.toUtf8(),GA_ReadOnly); ++ ++ if(nullptr == dataset) ++ { ++ QMessageBox::warning(canvas, tr("Error..."), tr("Failed to load file: %1").arg(filename)); ++ return; ++ } ++ ++ char str[1025] = {0}; ++ if(dataset->GetProjectionRef()) ++ { ++ strncpy(str, dataset->GetProjectionRef(), sizeof(str) - 1); ++ } ++ ++ { ++ OGRSpatialReference oSRS; ++ char *wkt = str; ++ oSRS.importFromWkt(&wkt); ++ ++ char *proj4 = nullptr; ++ oSRS.exportToProj4(&proj4); ++ proj4str = proj4; ++ pjsrc = pj_init_plus(proj4); ++ free(proj4); ++ } ++ ++ GDALRasterBand *pBand = dataset->GetRasterBand(1); ++ ++ if(nullptr == pBand) ++ { ++ GDALClose(dataset); ++ dataset = nullptr; ++ QMessageBox::warning(canvas, tr("Error..."), tr("Failed to load file: %1").arg(filename)); ++ return; ++ } ++ hasOverviews = pBand->GetOverviewCount(); ++ qDebug() << "hasOverviews" << hasOverviews; ++ ++ // ------- setup color table --------- ++ rasterBandCount = dataset->GetRasterCount(); ++ if(rasterBandCount == 1) ++ { ++ if(pBand->GetColorInterpretation() == GCI_PaletteIndex ) ++ { ++ GDALColorTable * pct = pBand->GetColorTable(); ++ for(int i=0; i < pct->GetColorEntryCount(); ++i) ++ { ++ const GDALColorEntry& e = *pct->GetColorEntry(i); ++ colortable << qRgba(e.c1, e.c2, e.c3, e.c4); ++ } ++ } ++ else if(pBand->GetColorInterpretation() == GCI_GrayIndex ) ++ { ++ for(int i=0; i < 256; ++i) ++ { ++ colortable << qRgba(i, i, i, 255); ++ } ++ } ++ else ++ { ++ GDALClose(dataset); ++ dataset = nullptr; ++ QMessageBox::warning(canvas, tr("Error..."), tr("File must be 8 bit palette or gray indexed.")); ++ return; ++ } ++ ++ int success = 0; ++ qreal idx = pBand->GetNoDataValue(&success); ++ if(success) ++ { ++ if((idx >= 0) && (idx < colortable.size())) ++ { ++ QColor tmp(colortable[idx]); ++ tmp.setAlpha(0); ++ colortable[idx] = tmp.rgba(); ++ hasNoData = idx; ++ } ++ else ++ { ++ qDebug() << "Index for no data value is out of bound"; ++ return; ++ } ++ } ++ } ++ qDebug() << "hasNoData" << hasNoData; ++ ++ xsize_px = dataset->GetRasterXSize(); ++ ysize_px = dataset->GetRasterYSize(); ++ ++ qreal adfGeoTransform[6]; ++ dataset->GetGeoTransform( adfGeoTransform ); ++ ++ xscale = adfGeoTransform[1]; ++ yscale = adfGeoTransform[5]; ++ xrot = adfGeoTransform[4]; ++ yrot = adfGeoTransform[2]; ++ ++ trFwd = QTransform(); ++ trFwd.translate(adfGeoTransform[0], adfGeoTransform[3]); ++ trFwd.scale(adfGeoTransform[1], adfGeoTransform[5]); ++ ++ if(adfGeoTransform[4] != 0.0) ++ { ++ trFwd.rotate(qAtan(adfGeoTransform[2]/adfGeoTransform[4])); ++ } ++ ++ trInv = trFwd.inverted(); ++ ++ ref1 = trFwd.map(QPointF(0,0)); ++ ref2 = trFwd.map(QPointF(xsize_px,0)); ++ ref3 = trFwd.map(QPointF(xsize_px,ysize_px)); ++ ref4 = trFwd.map(QPointF(0,ysize_px)); ++ ++ isValid = true; ++} ++ ++QString CGdalFile::getProjection() const ++{ ++ return proj4str; ++} ++ ++QString CGdalFile::getInfo() const ++{ ++ QString str; ++ QTextStream out(&str); ++ ++ if(proj4str.isEmpty()) ++ { ++ out << "no projection" << endl; ++ } ++ else ++ { ++ out << getProjection() << endl; ++ if(pj_is_latlong(pjsrc)) ++ { ++ out << "xscale: " << xscale << "px/rad\tyscale: " << yscale << "px/rad" << endl; ++ } ++ else ++ { ++ out << "xscale: " << xscale << "px/m\tyscale: " << yscale << "px/m" << endl; ++ } ++ } ++ ++ out << "num. bands:\t" << rasterBandCount << " "; ++ switch(rasterBandCount) ++ { ++ case 1: ++ out << tr("(color table)"); ++ break; ++ ++ case 3: ++ out << tr("(RGB)"); ++ break; ++ ++ case 4: ++ out << tr("(RGBA)"); ++ break; ++ ++ default: ++ out << tr("(unknown)"); ++ } ++ ++ out << endl; ++ ++ out << "has overviews:\t" << hasOverviews << endl; ++ ++ if((rasterBandCount != 4) && (hasNoData != -1)) ++ { ++ out << "has no data:\t" << hasNoData << endl; ++ } ++ ++ return str; ++} +diff --git a/src/qmaptool/helpers/CGdalFile.h b/src/qmaptool/helpers/CGdalFile.h +new file mode 100644 +index 00000000..49d77db2 +--- /dev/null ++++ b/src/qmaptool/helpers/CGdalFile.h +@@ -0,0 +1,93 @@ ++/********************************************************************************************** ++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CGDALFILE_H ++#define CGDALFILE_H ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++class GDALDataset; ++ ++class CGdalFile ++{ ++ Q_DECLARE_TR_FUNCTIONS(CGdalFile) ++public: ++ CGdalFile(); ++ virtual ~CGdalFile() = default; ++ ++ bool getIsValid() const ++ { ++ return isValid; ++ } ++ ++ QString getProjection() const; ++ ++protected: ++ virtual QString getInfo() const; ++ virtual void load(const QString& filename); ++ virtual void unload(); ++ ++ GDALDataset * dataset = nullptr; ++ ++ /// number of color bands used by the *vrt ++ int rasterBandCount = 0; ++ /// QT representation of the vrt's color table ++ QVector colortable; ++ ++ // true if the map file has overviews ++ qint32 hasOverviews = -1; ++ qint32 hasNoData = -1; ++ ++ ++ /// true if the map file could be loaded ++ bool isValid = false; ++ ++ /// width in number of px ++ qreal xsize_px = 0; ++ /// height in number of px ++ qreal ysize_px = 0; ++ ++ /// scale [px/m] ++ qreal xscale = 0; ++ /// scale [px/m] ++ qreal yscale = 0; ++ ++ qreal xrot = 0; ++ qreal yrot = 0; ++ ++ QPointF ref1; ++ QPointF ref2; ++ QPointF ref3; ++ QPointF ref4; ++ ++ QTransform trFwd; ++ QTransform trInv; ++ ++ QString proj4str; ++ ++ projPJ pjsrc = nullptr; ++}; ++ ++#endif //CGDALFILE_H ++ +diff --git a/src/qmaptool/helpers/CSettings.h b/src/qmaptool/helpers/CSettings.h +new file mode 100644 +index 00000000..6abe4ecd +--- /dev/null ++++ b/src/qmaptool/helpers/CSettings.h +@@ -0,0 +1,54 @@ ++/********************************************************************************************** ++ Copyright (C) 2012 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++#ifndef CSETTINGS_H ++#define CSETTINGS_H ++ ++#include "setup/CAppOpts.h" ++#include ++ ++class CSettings : public QObject ++{ ++public: ++ CSettings() ++ { ++ if(!qlOpts->configfile.isEmpty()) ++ { ++ cfg = new QSettings(qlOpts->configfile, QSettings::IniFormat, this); ++ } ++ else ++ { ++ cfg = new QSettings(this); ++ } ++ } ++ ~CSettings() ++ { ++ } ++ ++ QSettings& get() ++ { ++ return *cfg; ++ } ++ ++private: ++ QSettings * cfg; ++}; ++ ++#define SETTINGS \ ++ CSettings ccfg; \ ++ QSettings& cfg = ccfg.get() ++#endif //CSETTINGS_H +diff --git a/src/qmaptool/helpers/mitab.cpp b/src/qmaptool/helpers/mitab.cpp +new file mode 100644 +index 00000000..4569a17d +--- /dev/null ++++ b/src/qmaptool/helpers/mitab.cpp +@@ -0,0 +1,260 @@ ++/********************************************************************************************** ++ Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++#include "mitab.h" ++ ++const MapInfoDatumInfo asDatumInfoListQL[] = ++{ ++ { // Datum ignore ++ 0, "", 29, 0, 0, 0, 0, 0, 0, 0, 0 ++ }, ++ {74, "North_American_Datum_1983", 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {1, "Adindan", 6, -162, -12, 206, 0, 0, 0, 0, 0}, ++ {2, "Afgooye", 3, -43, -163, 45, 0, 0, 0, 0, 0}, ++ {3, "Ain_el_Abd_1970", 4, -150, -251, -2, 0, 0, 0, 0, 0}, ++ {4, "Anna_1_Astro_1965", 2, -491, -22, 435, 0, 0, 0, 0, 0}, ++ {5, "Arc_1950", 15,-143, -90, -294,0, 0, 0, 0, 0}, ++ {6, "Arc_1960", 6, -160, -8, -300,0, 0, 0, 0, 0}, ++ {7, "Ascension_Islands", 4, -207, 107, 52, 0, 0, 0, 0, 0}, ++ {8, "Astro_Beacon_E", 4, 145, 75, -272,0, 0, 0, 0, 0}, ++ {9, "Astro_B4_Sorol_Atoll", 4, 114, -116, -333,0, 0, 0, 0, 0}, ++ {10, "Astro_Dos_71_4", 4, -320, 550, -494,0, 0, 0, 0, 0}, ++ {11, "Astronomic_Station_1952", 4, 124, -234, -25, 0, 0, 0, 0, 0}, ++ {12, "Australian_Geodetic_Datum_66",2, -133, -48, 148, 0, 0, 0, 0, 0}, ++ {13, "Australian_Geodetic_Datum_84",2, -134, -48, 149, 0, 0, 0, 0, 0}, ++ {14, "Bellevue_Ign", 4, -127, -769, 472, 0, 0, 0, 0, 0}, ++ {15, "Bermuda_1957", 7, -73, 213, 296, 0, 0, 0, 0, 0}, ++ {16, "Bogota", 4, 307, 304, -318,0, 0, 0, 0, 0}, ++ {17, "Campo_Inchauspe", 4, -148, 136, 90, 0, 0, 0, 0, 0}, ++ {18, "Canton_Astro_1966", 4, 298, -304, -375,0, 0, 0, 0, 0}, ++ {19, "Cape", 6, -136, -108, -292,0, 0, 0, 0, 0}, ++ {20, "Cape_Canaveral", 7, -2, 150, 181, 0, 0, 0, 0, 0}, ++ {21, "Carthage", 6, -263, 6, 431, 0, 0, 0, 0, 0}, ++ {22, "Chatham_1971", 4, 175, -38, 113, 0, 0, 0, 0, 0}, ++ {23, "Chua", 4, -134, 229, -29, 0, 0, 0, 0, 0}, ++ {24, "Corrego_Alegre", 4, -206, 172, -6, 0, 0, 0, 0, 0}, ++ {25, "Batavia", 10,-377,681, -50, 0, 0, 0, 0, 0}, ++ {26, "Dos_1968", 4, 230, -199, -752,0, 0, 0, 0, 0}, ++ {27, "Easter_Island_1967", 4, 211, 147, 111, 0, 0, 0, 0, 0}, ++ {28, "European_Datum_1950", 4, -87, -98, -121,0, 0, 0, 0, 0}, ++ {29, "European_Datum_1979", 4, -86, -98, -119,0, 0, 0, 0, 0}, ++ {30, "Gandajika_1970", 4, -133, -321, 50, 0, 0, 0, 0, 0}, ++ {31, "New_Zealand_GD49", 4, 84, -22, 209, 0, 0, 0, 0, 0}, ++ {32, "GRS_67", 21,0, 0, 0, 0, 0, 0, 0, 0}, ++ {33, "GRS_80", 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {34, "Guam_1963", 7, -100, -248, 259, 0, 0, 0, 0, 0}, ++ {35, "Gux_1_Astro", 4, 252, -209, -751,0, 0, 0, 0, 0}, ++ {36, "Hito_XVIII_1963", 4, 16, 196, 93, 0, 0, 0, 0, 0}, ++ {37, "Hjorsey_1955", 4, -73, 46, -86, 0, 0, 0, 0, 0}, ++ {38, "Hong_Kong_1963", 4, -156, -271, -189,0, 0, 0, 0, 0}, ++ {39, "Hu_Tzu_Shan", 4, -634, -549, -201,0, 0, 0, 0, 0}, ++ {40, "Indian_Thailand_Vietnam", 11,214, 836, 303, 0, 0, 0, 0, 0}, ++ {41, "Indian_Bangladesh", 11,289, 734, 257, 0, 0, 0, 0, 0}, ++ {42, "Ireland_1965", 13,506, -122, 611, 0, 0, 0, 0, 0}, ++ {43, "ISTS_073_Astro_1969", 4, 208, -435, -229,0, 0, 0, 0, 0}, ++ {44, "Johnston_Island_1961", 4, 191, -77, -204,0, 0, 0, 0, 0}, ++ {45, "Kandawala", 11,-97, 787, 86, 0, 0, 0, 0, 0}, ++ {46, "Kerguyelen_Island", 4, 145, -187, 103, 0, 0, 0, 0, 0}, ++ {47, "Kertau", 17,-11, 851, 5, 0, 0, 0, 0, 0}, ++ {48, "L_C_5_Astro", 7, 42, 124, 147, 0, 0, 0, 0, 0}, ++ {49, "Liberia_1964", 6, -90, 40, 88, 0, 0, 0, 0, 0}, ++ {50, "Luzon_Phillippines", 7, -133, -77, -51, 0, 0, 0, 0, 0}, ++ {51, "Luzon_Mindanao_Island", 7, -133, -79, -72, 0, 0, 0, 0, 0}, ++ {52, "Mahe_1971", 6, 41, -220, -134,0, 0, 0, 0, 0}, ++ {53, "Marco_Astro", 4, -289, -124, 60, 0, 0, 0, 0, 0}, ++ {54, "Massawa", 10,639, 405, 60, 0, 0, 0, 0, 0}, ++ {55, "Merchich", 16,31, 146, 47, 0, 0, 0, 0, 0}, ++ {56, "Midway_Astro_1961", 4, 912, -58, 1227,0, 0, 0, 0, 0}, ++ {57, "Minna", 6, -92, -93, 122, 0, 0, 0, 0, 0}, ++ {58, "Nahrwan_Masirah_Island", 6, -247, -148, 369, 0, 0, 0, 0, 0}, ++ {59, "Nahrwan_Un_Arab_Emirates", 6, -249, -156, 381, 0, 0, 0, 0, 0}, ++ {60, "Nahrwan_Saudi_Arabia", 6, -231, -196, 482, 0, 0, 0, 0, 0}, ++ {61, "Naparima_1972", 4, -2, 374, 172, 0, 0, 0, 0, 0}, ++ {62, "NAD_1927", 7, -8, 160, 176, 0, 0, 0, 0, 0}, ++ {62, "North_American_Datum_1927", 7, -8, 160, 176, 0, 0, 0, 0, 0}, ++ {63, "NAD_27_Alaska", 7, -5, 135, 172, 0, 0, 0, 0, 0}, ++ {64, "NAD_27_Bahamas", 7, -4, 154, 178, 0, 0, 0, 0, 0}, ++ {65, "NAD_27_San_Salvador", 7, 1, 140, 165, 0, 0, 0, 0, 0}, ++ {66, "NAD_27_Canada", 7, -10, 158, 187, 0, 0, 0, 0, 0}, ++ {67, "NAD_27_Canal_Zone", 7, 0, 125, 201, 0, 0, 0, 0, 0}, ++ {68, "NAD_27_Caribbean", 7, -7, 152, 178, 0, 0, 0, 0, 0}, ++ {69, "NAD_27_Central_America", 7, 0, 125, 194, 0, 0, 0, 0, 0}, ++ {70, "NAD_27_Cuba", 7, -9, 152, 178, 0, 0, 0, 0, 0}, ++ {71, "NAD_27_Greenland", 7, 11, 114, 195, 0, 0, 0, 0, 0}, ++ {72, "NAD_27_Mexico", 7, -12, 130, 190, 0, 0, 0, 0, 0}, ++ {73, "NAD_27_Michigan", 8, -8, 160, 176, 0, 0, 0, 0, 0}, ++ {75, "Observatorio_1966", 4, -425, -169, 81, 0, 0, 0, 0, 0}, ++ {76, "Old_Egyptian", 22,-130, 110, -13, 0, 0, 0, 0, 0}, ++ {77, "Old_Hawaiian", 7, 61, -285, -181,0, 0, 0, 0, 0}, ++ {78, "Oman", 6, -346, -1, 224, 0, 0, 0, 0, 0}, ++ {79, "OSGB_1936", 9, 375, -111, 431, 0, 0, 0, 0, 0}, ++ {80, "Pico_De_Las_Nieves", 4, -307, -92, 127, 0, 0, 0, 0, 0}, ++ {81, "Pitcairn_Astro_1967", 4, 185, 165, 42, 0, 0, 0, 0, 0}, ++ {82, "Provisional_South_American", 4, -288, 175, -376,0, 0, 0, 0, 0}, ++ {83, "Puerto_Rico", 7, 11, 72, -101,0, 0, 0, 0, 0}, ++ {84, "Qatar_National", 4, -128, -283, 22, 0, 0, 0, 0, 0}, ++ {85, "Qornoq", 4, 164, 138, -189, 0, 0, 0, 0, 0}, ++ {86, "Reunion", 4, 94, -948,-1262,0, 0, 0, 0, 0}, ++ {87, "Monte_Mario", 4, -225, -65, 9, 0, 0, 0, 0, 0}, ++ {88, "Santo_Dos", 4, 170, 42, 84, 0, 0, 0, 0, 0}, ++ {89, "Sao_Braz", 4, -203, 141, 53, 0, 0, 0, 0, 0}, ++ {90, "Sapper_Hill_1943", 4, -355, 16, 74, 0, 0, 0, 0, 0}, ++ {91, "Schwarzeck", 14,616, 97, -251, 0, 0, 0, 0, 0}, ++ {92, "South_American_Datum_1969", 24,-57, 1, -41, 0, 0, 0, 0, 0}, ++ {93, "South_Asia", 19,7, -10, -26, 0, 0, 0, 0, 0}, ++ {94, "Southeast_Base", 4, -499, -249,314, 0, 0, 0, 0, 0}, ++ {95, "Southwest_Base", 4, -104, 167, -38, 0, 0, 0, 0, 0}, ++ {96, "Timbalai_1948", 11,-689, 691, -46, 0, 0, 0, 0, 0}, ++ {97, "Tokyo", 10,-128, 481, 664, 0, 0, 0, 0, 0}, ++ {98, "Tristan_Astro_1968", 4, -632, 438, -609, 0, 0, 0, 0, 0}, ++ {99, "Viti_Levu_1916", 6, 51, 391, -36, 0, 0, 0, 0, 0}, ++ {100, "Wake_Entiwetok_1960", 23,101, 52, -39, 0, 0, 0, 0, 0}, ++ {101, "WGS_60", 26,0, 0, 0, 0, 0, 0, 0, 0}, ++ {102, "WGS_66", 27,0, 0, 0, 0, 0, 0, 0, 0}, ++ {103, "WGS_1972", 1, 0, 8, 10, 0, 0, 0, 0, 0}, ++ {104, "WGS_1984", 28,0, 0, 0, 0, 0, 0, 0, 0}, ++ {105, "Yacare", 4, -155, 171, 37, 0, 0, 0, 0, 0}, ++ {106, "Zanderij", 4, -265, 120, -358, 0, 0, 0, 0, 0}, ++ {107, "NTF", 30,-168, -60, 320, 0, 0, 0, 0, 0}, ++ {108, "European_Datum_1987", 4, -83, -96, -113, 0, 0, 0, 0, 0}, ++ {109, "Netherlands_Bessel", 10,593, 26, 478, 0, 0, 0, 0, 0}, ++ {110, "Belgium_Hayford", 4, 81, 120, 129, 0, 0, 0, 0, 0}, ++ {111, "NWGL_10", 1, -1, 15, 1, 0, 0, 0, 0, 0}, ++ {112, "Rikets_koordinatsystem_1990",10,498, -36, 568, 0, 0, 0, 0, 0}, ++ {113, "Lisboa_DLX", 4, -303, -62, 105, 0, 0, 0, 0, 0}, ++ {114, "Melrica_1973_D73", 4, -223, 110, 37, 0, 0, 0, 0, 0}, ++ {115, "Euref_98", 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {116, "GDA94", 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {117, "NZGD2000", 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {118, "America_Samoa", 7, -115, 118, 426, 0, 0, 0, 0, 0}, ++ {119, "Antigua_Astro_1965", 6, -270, 13, 62, 0, 0, 0, 0, 0}, ++ {120, "Ayabelle_Lighthouse", 6, -79, -129, 145, 0, 0, 0, 0, 0}, ++ {121, "Bukit_Rimpah", 10,-384, 664, -48, 0, 0, 0, 0, 0}, ++ {122, "Estonia_1937", 10,374, 150, 588, 0, 0, 0, 0, 0}, ++ {123, "Dabola", 6, -83, 37, 124, 0, 0, 0, 0, 0}, ++ {124, "Deception_Island", 6, 260, 12, -147, 0, 0, 0, 0, 0}, ++ {125, "Fort_Thomas_1955", 6, -7, 215, 225, 0, 0, 0, 0, 0}, ++ {126, "Graciosa_base_1948", 4, -104, 167, -38, 0, 0, 0, 0, 0}, ++ {127, "Herat_North", 4, -333, -222,114, 0, 0, 0, 0, 0}, ++ {128, "Hermanns_Kogel", 10,682, -203, 480, 0, 0, 0, 0, 0}, ++ {129, "Indian", 50,283, 682, 231, 0, 0, 0, 0, 0}, ++ {130, "Indian_1954", 11,217, 823, 299, 0, 0, 0, 0, 0}, ++ {131, "Indian_1960", 11,198, 881, 317, 0, 0, 0, 0, 0}, ++ {132, "Indian_1975", 11,210, 814, 289, 0, 0, 0, 0, 0}, ++ {133, "Indonesian_Datum_1974", 4, -24, -15, 5, 0, 0, 0, 0, 0}, ++ {134, "ISTS061_Astro_1968", 4, -794, 119, -298, 0, 0, 0, 0, 0}, ++ {135, "Kusaie_Astro_1951", 4, 647, 1777, -1124,0, 0, 0, 0, 0}, ++ {136, "Leigon", 6, -130, 29, 364, 0, 0, 0, 0, 0}, ++ {137, "Montserrat_Astro_1958", 6, 174, 359, 365, 0, 0, 0, 0, 0}, ++ {138, "Mporaloko", 6, -74, -130, 42, 0, 0, 0, 0, 0}, ++ {139, "North_Sahara_1959", 6, -186, -93, 310, 0, 0, 0, 0, 0}, ++ {140, "Observatorio_Met_1939", 4, -425, -169,81, 0, 0, 0, 0, 0}, ++ {141, "Point_58", 6, -106, -129,165, 0, 0, 0, 0, 0}, ++ {142, "Pointe_Noire", 6, -148, 51, -291, 0, 0, 0, 0, 0}, ++ {143, "Porto_Santo_1936", 4, -499, -249,314, 0, 0, 0, 0, 0}, ++ {144, "Selvagem_Grande_1938", 4, -289, -124,60, 0, 0, 0, 0, 0}, ++ {145, "Sierra_Leone_1960", 6, -88, 4, 101, 0, 0, 0, 0, 0}, ++ {146, "S_JTSK_Ferro", 10, 589, 76, 480, 0, 0, 0, 0, 0}, ++ {147, "Tananarive_1925", 4, -189, -242,-91, 0, 0, 0, 0, 0}, ++ {148, "Voirol_1874", 6, -73, -247,227, 0, 0, 0, 0, 0}, ++ {149, "Virol_1960", 6, -123, -206,219, 0, 0, 0, 0, 0}, ++ {150, "Hartebeesthoek94", 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {151, "ATS77", 51, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {152, "JGD2000", 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {1000,"DHDN_Potsdam_Rauenberg", 10,582, 105, 414, -1.04, -0.35, 3.08, 8.3, 0}, ++ {1001,"Pulkovo_1942", 3, 24, -123, -94, -0.02, 0.25, 0.13, 1.1, 0}, ++ {1002,"NTF_Paris_Meridian", 30,-168, -60, 320, 0, 0, 0, 0, 2.337229166667}, ++ {1003,"Switzerland_CH_1903", 10,660.077,13.551, 369.344, 0.804816, 0.577692, 0.952236, 5.66,0}, ++ {1004,"Hungarian_Datum_1972", 21,-56, 75.77, 15.31, -0.37, -0.2, -0.21, -1.01, 0}, ++ {1005,"Cape_7_Parameter", 28,-134.73,-110.92, -292.66, 0, 0, 0, 1, 0}, ++ {1006,"AGD84_7_Param_Aust", 2, -117.763,-51.51, 139.061, -0.292, -0.443, -0.277, -0.191, 0}, ++ {1007,"AGD66_7_Param_ACT", 2, -129.193,-41.212, 130.73, -0.246, -0.374, -0.329, -2.955, 0}, ++ {1008,"AGD66_7_Param_TAS", 2, -120.271,-64.543, 161.632, -0.2175, 0.0672, 0.1291, 2.4985, 0}, ++ {1009,"AGD66_7_Param_VIC_NSW", 2, -119.353,-48.301, 139.484, -0.415, -0.26, -0.437, -0.613, 0}, ++ {1010,"NZGD_7_Param_49", 4, 59.47, -5.04, 187.44, -0.47, 0.1, -1.024, -4.5993, 0}, ++ {1011,"Rikets_Tri_7_Param_1990", 10,419.3836, 99.3335, 591.3451, -0.850389, -1.817277, 7.862238, -0.99496, 0}, ++ {1012,"Russia_PZ90", 52, -1.08,-0.27,-0.9,0, 0, -0.16,-0.12, 0}, ++ {1013,"Russia_SK42", 52, 23.92,-141.27,-80.9, 0, -0.35,-0.82, -0.12, 0}, ++ {1014,"Russia_SK95", 52, 24.82,-131.21,-82.66,0,0,-0.16,-0.12, 0}, ++ {1015,"Tokyo", 10, -146.414, 507.337, 680.507,0,0,0,0,0}, ++ {1016,"Finnish_KKJ", 4, -96.062, -82.428, -121.754, -4.801, -0.345, 1.376, 1.496, 0}, ++ ++ {-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} ++}; ++ ++/* -------------------------------------------------------------------- */ ++/* This table was hand entered from Appendix I of the mapinfo 6 */ ++/* manuals. */ ++/* -------------------------------------------------------------------- */ ++ ++const MapInfoSpheroidInfo asSpheroidInfoList[] = ++{ ++ { 9,"Airy 1930", 6377563.396, 299.3249646}, ++ {13,"Airy 1930 (modified for Ireland 1965", 6377340.189, 299.3249646}, ++ {51,"ATS77 (Average Terrestrial System 1977)", 6378135, 298.257}, ++ { 2,"Australian", 6378160.0, 298.25}, ++ {10,"Bessel 1841", 6377397.155, 299.1528128}, ++ {35,"Bessel 1841 (modified for NGO 1948)", 6377492.0176, 299.15281}, ++ {14,"Bessel 1841 (modified for Schwarzeck)", 6377483.865, 299.1528128}, ++ {36,"Clarke 1858", 6378293.639, 294.26068}, ++ { 7,"Clarke 1866", 6378206.4, 294.9786982}, ++ { 8,"Clarke 1866 (modified for Michigan)", 6378450.047484481,294.9786982}, ++ { 6,"Clarke 1880", 6378249.145, 293.465}, ++ {15,"Clarke 1880 (modified for Arc 1950)", 6378249.145326, 293.4663076}, ++ {30,"Clarke 1880 (modified for IGN)", 6378249.2, 293.4660213}, ++ {37,"Clarke 1880 (modified for Jamaica)", 6378249.136, 293.46631}, ++ {16,"Clarke 1880 (modified for Merchich)", 6378249.2, 293.46598}, ++ {38,"Clarke 1880 (modified for Palestine)", 6378300.79, 293.46623}, ++ {39,"Everest (Brunei and East Malaysia)", 6377298.556, 300.8017}, ++ {11,"Everest (India 1830)", 6377276.345, 300.8017}, ++ {40,"Everest (India 1956)", 6377301.243, 300.80174}, ++ {50,"Everest (Pakistan)", 6377309.613, 300.8017}, ++ {17,"Everest (W. Malaysia and Singapore 1948)", 6377304.063, 300.8017}, ++ {48,"Everest (West Malaysia 1969)", 6377304.063, 300.8017}, ++ {18,"Fischer 1960", 6378166.0, 298.3}, ++ {19,"Fischer 1960 (modified for South Asia)", 6378155.0, 298.3}, ++ {20,"Fischer 1968", 6378150.0, 298.3}, ++ {21,"GRS 67", 6378160.0, 298.247167427}, ++ { 0,"GRS 80", 6378137.0, 298.257222101}, ++ { 5,"Hayford", 6378388.0, 297.0}, ++ {22,"Helmert 1906", 6378200.0, 298.3}, ++ {23,"Hough", 6378270.0, 297.0}, ++ {31,"IAG 75", 6378140.0, 298.257222}, ++ {41,"Indonesian", 6378160.0, 298.247}, ++ { 4,"International 1924", 6378388.0, 297.0}, ++ {49,"Irish (WOFO)", 6377542.178, 299.325}, ++ { 3,"Krassovsky", 6378245.0, 298.3}, ++ {32,"MERIT 83", 6378137.0, 298.257}, ++ {33,"New International 1967", 6378157.5, 298.25}, ++ {42,"NWL 9D", 6378145.0, 298.25}, ++ {43,"NWL 10D", 6378135.0, 298.26}, ++ {44,"OSU86F", 6378136.2, 298.25722}, ++ {45,"OSU91A", 6378136.3, 298.25722}, ++ {46,"Plessis 1817", 6376523.0, 308.64}, ++ {52,"PZ90", 6378136.0, 298.257839303}, ++ {24,"South American", 6378160.0, 298.25}, ++ {12,"Sphere", 6370997.0, 0.0}, ++ {47,"Struve 1860", 6378297.0, 294.73}, ++ {34,"Walbeck", 6376896.0, 302.78}, ++ {25,"War Office", 6378300.583, 296.0}, ++ {26,"WGS 60", 6378165.0, 298.3}, ++ {27,"WGS 66", 6378145.0, 298.25}, ++ { 1,"WGS 72", 6378135.0, 298.26}, ++ {28,"WGS 84", 6378137.0, 298.257223563}, ++ {29,"WGS 84 (MAPINFO Datum 0)", 6378137.01, 298.257223563}, ++ {-1,0, 0.0, 0.0} ++}; +diff --git a/src/qmaptool/helpers/mitab.h b/src/qmaptool/helpers/mitab.h +new file mode 100644 +index 00000000..6229b557 +--- /dev/null ++++ b/src/qmaptool/helpers/mitab.h +@@ -0,0 +1,46 @@ ++/********************************************************************************************** ++ Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++#ifndef MITAB_H ++#define MITAB_H ++ ++struct MapInfoDatumInfo ++{ ++ int nMapInfoDatumID; ++ const char *pszOGCDatumName; ++ int nEllipsoid; ++ double dfShiftX; ++ double dfShiftY; ++ double dfShiftZ; ++ double dfDatumParm0; /* RotX */ ++ double dfDatumParm1; /* RotY */ ++ double dfDatumParm2; /* RotZ */ ++ double dfDatumParm3; /* Scale Factor */ ++ double dfDatumParm4; /* Prime Meridian */ ++}; ++ ++struct MapInfoSpheroidInfo ++{ ++ int nMapInfoId; ++ const char *pszMapinfoName; ++ double dfA; /* semi major axis in meters */ ++ double dfInvFlattening; /* Inverse flattening */ ++}; ++ ++extern const MapInfoDatumInfo asDatumInfoListQL[]; ++extern const MapInfoSpheroidInfo asSpheroidInfoList[]; ++#endif //MITAB_H +diff --git a/src/qmaptool/items/CItemCutMap.cpp b/src/qmaptool/items/CItemCutMap.cpp +new file mode 100644 +index 00000000..197b81b2 +--- /dev/null ++++ b/src/qmaptool/items/CItemCutMap.cpp +@@ -0,0 +1,97 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "items/CItemCutMap.h" ++#include "overlay/COverlayCutMap.h" ++ ++#include ++ ++CItemCutMap::CItemCutMap(const QString &filename, QStackedWidget *stackedWidget, QListWidget *parent) ++ : CItemFile(filename, parent) ++{ ++ overlay = new COverlayCutMap(this, stackedWidget); ++ connect(overlay, &COverlayCutMap::sigChanged, this, &CItemCutMap::sigChanged); ++} ++ ++CItemCutMap::~CItemCutMap() ++{ ++ overlay->deleteLater(); ++} ++ ++void CItemCutMap::saveSettings(QSettings& cfg) ++{ ++ CItemFile::saveSettings(cfg); ++ overlay->saveSettings(cfg); ++} ++ ++void CItemCutMap::loadSettings(QSettings& cfg) ++{ ++ CItemFile::loadSettings(cfg); ++ overlay->loadSettings(cfg); ++} ++ ++void CItemCutMap::toFront() ++{ ++ overlay->toFront(); ++} ++ ++bool CItemCutMap::drawFx(QPainter& p, CCanvas::redraw_e needsRedraw) ++{ ++ CItemFile::drawFx(p, needsRedraw); ++ overlay->drawFx(p, needsRedraw); ++ return true; ++} ++ ++void CItemCutMap::mouseMoveEventFx(QMouseEvent *e) ++{ ++ CItemFile::mouseMoveEventFx(e); ++ if(!mapIsMoving) ++ { ++ overlay->mouseMoveEventFx(e); ++ } ++} ++ ++void CItemCutMap::mouseReleaseEventFx(QMouseEvent *e) ++{ ++ if(!mapDidMove) ++ { ++ overlay->mouseReleaseEventFx(e); ++ } ++ CItemFile::mouseReleaseEventFx(e); ++} ++ ++void CItemCutMap::leaveEventFx(QEvent *e) ++{ ++ CItemFile::leaveEventFx(e); ++ overlay->abortStep(); ++} ++ ++QCursor CItemCutMap::getCursorFx() ++{ ++ return overlay->getCursorFx(); ++} ++ ++void CItemCutMap::saveShape(const QString& filename) const ++{ ++ overlay->saveShape(filename); ++} ++ ++bool CItemCutMap::isOk() const ++{ ++ return overlay->isOk(); ++} +diff --git a/src/qmaptool/items/CItemCutMap.h b/src/qmaptool/items/CItemCutMap.h +new file mode 100644 +index 00000000..851589b3 +--- /dev/null ++++ b/src/qmaptool/items/CItemCutMap.h +@@ -0,0 +1,52 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CITEMCUTMAP_H ++#define CITEMCUTMAP_H ++ ++#include "items/CItemFile.h" ++ ++class COverlayCutMap; ++ ++class CItemCutMap : public CItemFile ++{ ++public: ++ CItemCutMap(const QString& filename, QStackedWidget * stackedWidget, QListWidget *parent); ++ virtual ~CItemCutMap(); ++ ++ void saveSettings(QSettings& cfg) override; ++ void loadSettings(QSettings& cfg) override; ++ ++ void toFront() override; ++ ++ bool drawFx(QPainter& p, CCanvas::redraw_e needsRedraw) override; ++ void mouseMoveEventFx(QMouseEvent *e) override; ++ void mouseReleaseEventFx(QMouseEvent *e) override; ++ void leaveEventFx(QEvent *e) override; ++ QCursor getCursorFx() override; ++ ++ void saveShape(const QString& filename) const; ++ ++ bool isOk() const override; ++ ++private: ++ COverlayCutMap * overlay; ++}; ++ ++#endif //CITEMCUTMAP_H ++ +diff --git a/src/qmaptool/items/CItemFile.cpp b/src/qmaptool/items/CItemFile.cpp +new file mode 100644 +index 00000000..3aeff434 +--- /dev/null ++++ b/src/qmaptool/items/CItemFile.cpp +@@ -0,0 +1,37 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "canvas/CDrawContextPixel.h" ++#include "CMainWindow.h" ++#include "items/CItemFile.h" ++ ++CItemFile::CItemFile(const QString &filename, QListWidget *parent) ++ : IItem(filename) ++ , QListWidgetItem(parent) ++{ ++ setText(QFileInfo(filename).completeBaseName()); ++ drawContext = new CDrawContextPixel(CMainWindow::self().getCanvas(), this); ++ reload(); ++} ++ ++ ++void CItemFile::reload() ++{ ++ IItem::reload(); ++ setToolTip(filename + "\n" + drawContext->getInfo()); ++} +diff --git a/src/qmaptool/items/CItemFile.h b/src/qmaptool/items/CItemFile.h +new file mode 100644 +index 00000000..66b31321 +--- /dev/null ++++ b/src/qmaptool/items/CItemFile.h +@@ -0,0 +1,38 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CITEMFILE_H ++#define CITEMFILE_H ++ ++#include "items/IItem.h" ++ ++#include ++ ++class CItemFile : public IItem, public QListWidgetItem ++{ ++public: ++ CItemFile(const QString& filename, QListWidget *parent); ++ virtual ~CItemFile() = default; ++ ++ void setupChanged() override {} ++ ++ void reload() override; ++}; ++ ++#endif //CITEMFILE_H ++ +diff --git a/src/qmaptool/items/CItemListWidget.cpp b/src/qmaptool/items/CItemListWidget.cpp +new file mode 100644 +index 00000000..5776be22 +--- /dev/null ++++ b/src/qmaptool/items/CItemListWidget.cpp +@@ -0,0 +1,157 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "helpers/CSettings.h" ++#include "items/CItemListWidget.h" ++#include "items/IItem.h" ++ ++ ++#include ++ ++CItemListWidget::CItemListWidget(QWidget *parent) ++ : QWidget(parent) ++{ ++ setupUi(this); ++ ++ connect(toolFiles, &QToolButton::clicked, this, &CItemListWidget::slotFiles); ++ connect(toolDelFile, &QToolButton::clicked, this, &CItemListWidget::slotDeleteFile); ++ connect(toolDelFiles, &QToolButton::clicked, this, &CItemListWidget::slotDeleteFiles); ++ connect(toolReloadFile, &QToolButton::clicked, this, &CItemListWidget::slotLoadCurrentMap); ++ connect(listFiles, &QListWidget::itemSelectionChanged, this, &CItemListWidget::slotSelectionChanged); ++} ++ ++void CItemListWidget::saveSettings(QSettings& cfg) ++{ ++ QStringList files; ++ const int N = listFiles->count(); ++ for(int n = 0; n < N; n++) ++ { ++ IItem * item = dynamic_cast(listFiles->item(n)); ++ if(item != nullptr) ++ { ++ files << item->getFilename(); ++ cfg.beginGroup(QString("%1").arg(n)); ++ item->saveSettings(cfg); ++ cfg.endGroup(); ++ } ++ } ++ cfg.setValue("files", files); ++ cfg.setValue("lastFile", listFiles->currentRow()); ++} ++ ++void CItemListWidget::loadSettings(QSettings& cfg) ++{ ++ QStringList files = cfg.value("files", QStringList()).toStringList(); ++ addFiles(files); ++ ++ const int N = listFiles->count(); ++ for(int n = 0; n < N; n++) ++ { ++ IItem * item = dynamic_cast(listFiles->item(n)); ++ if(item != nullptr) ++ { ++ cfg.beginGroup(QString("%1").arg(n)); ++ item->loadSettings(cfg); ++ cfg.endGroup(); ++ } ++ } ++ ++ listFiles->setCurrentRow(cfg.value("lastFile",0).toInt()); ++} ++ ++IItem * CItemListWidget::currentItem() ++{ ++ return dynamic_cast(listFiles->currentItem()); ++} ++ ++IItem * CItemListWidget::item(int n) ++{ ++ return dynamic_cast(listFiles->item(n)); ++} ++ ++void CItemListWidget::addFiles(const QStringList& files) ++{ ++ for(const QString& file : files) ++ { ++ emit sigAddItem(file, listFiles); ++ } ++ ++ listFiles->setCurrentRow(listFiles->count() - 1); ++ slotSelectionChanged(); ++} ++ ++void CItemListWidget::slotFiles() ++{ ++ SETTINGS; ++ QString path = cfg.value("Path/mapInput", QDir::homePath()).toString(); ++ ++ const QStringList& files = QFileDialog::getOpenFileNames(this, tr("Select files..."), path); ++ if(files.isEmpty()) ++ { ++ return; ++ } ++ ++ cfg.setValue("Path/mapInput", QFileInfo(files.first()).absolutePath()); ++ addFiles(files); ++ ++ if(listFiles->count() && (listFiles->currentItem() ==nullptr)) ++ { ++ listFiles->setCurrentRow(0); ++ } ++} ++ ++void CItemListWidget::slotLoadCurrentMap() ++{ ++ IItem * item = dynamic_cast(listFiles->currentItem()); ++ if(item != nullptr) ++ { ++ item->reload(); ++ } ++} ++ ++void CItemListWidget::slotDeleteFiles() ++{ ++ listFiles->clear(); ++ slotSelectionChanged(); ++} ++ ++void CItemListWidget::slotDeleteFile() ++{ ++ QListWidgetItem * item = listFiles->takeItem(listFiles->currentRow()); ++ delete item; ++ slotSelectionChanged(); ++} ++ ++void CItemListWidget::slotSelectionChanged() ++{ ++ IItem * item = dynamic_cast(listFiles->currentItem()); ++ if(item != nullptr) ++ { ++ item->toFront(); ++ } ++ ++ bool isNotEmpty = listFiles->count() != 0; ++ int row = listFiles->currentRow(); ++ ++ toolDelFile->setEnabled(row != -1); ++ toolDelFiles->setEnabled(isNotEmpty); ++ toolReloadFile->setEnabled(row != -1); ++ ++ emit sigSelectionChanged(); ++} ++ +diff --git a/src/qmaptool/items/CItemListWidget.h b/src/qmaptool/items/CItemListWidget.h +new file mode 100644 +index 00000000..ad5123b1 +--- /dev/null ++++ b/src/qmaptool/items/CItemListWidget.h +@@ -0,0 +1,84 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CITEMLISTWIDGET_H ++#define CITEMLISTWIDGET_H ++ ++#include "ui_IItemListWidget.h" ++ ++class QSettings; ++class IItem; ++ ++class CItemListWidget : public QWidget, private Ui::IItemListWidget ++{ ++ Q_OBJECT ++public: ++ CItemListWidget(QWidget * parent); ++ virtual ~CItemListWidget() = default; ++ ++ void saveSettings(QSettings& cfg); ++ void loadSettings(QSettings& cfg); ++ ++ IItem * currentItem(); ++ IItem * item(int n); ++ ++ qint32 count() const ++ { ++ return listFiles->count(); ++ } ++ ++ template< typename LessThan> ++ void sort(LessThan lessThan) ++ { ++ listFiles->blockSignals(true); ++ ++ QList items; ++ while(listFiles->count() != 0) ++ { ++ items << listFiles->takeItem(0); ++ } ++ ++ qSort(items.begin(), items.end(), lessThan); ++ ++ for(QListWidgetItem* item : items) ++ { ++ listFiles->addItem(item); ++ } ++ ++ listFiles->blockSignals(false); ++ } ++ ++ ++signals: ++ void sigAddItem(const QString& filename, QListWidget * list); ++ void sigSelectionChanged(); ++ void sigChanged(); ++ ++protected slots: ++ void slotFiles(); ++ void slotLoadCurrentMap(); ++ void slotDeleteFiles(); ++ void slotDeleteFile(); ++ void slotSelectionChanged(); ++ ++protected: ++ void addFiles(const QStringList& files); ++}; ++ ++#endif //CITEMLISTWIDGET_H ++ +diff --git a/src/qmaptool/items/CItemMap.cpp b/src/qmaptool/items/CItemMap.cpp +new file mode 100644 +index 00000000..db007897 +--- /dev/null ++++ b/src/qmaptool/items/CItemMap.cpp +@@ -0,0 +1,82 @@ ++/********************************************************************************************** ++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "canvas/CCanvas.h" ++#include "canvas/IDrawContext.h" ++#include "CMainWindow.h" ++#include "items/CItemMap.h" ++#include "items/CItemMapLayer.h" ++#include "items/CItemTreeWidget.h" ++ ++#include ++ ++CItemMap::CItemMap(const QString &filename) ++ : IItem(filename) ++{ ++ setText(CItemTreeWidget::eColumnName, QFileInfo(filename).completeBaseName()); ++ setIcon(CItemTreeWidget::eColumnName, QIcon("://icons/32x32/FolderMap.png")); ++ ++ reload(); ++} ++ ++CItemMap::~CItemMap() ++{ ++ unload(); ++} ++ ++QPointF CItemMap::getScale() const ++{ ++ return QPointF(xscale, yscale); ++} ++ ++void CItemMap::reload() ++{ ++ load(filename); ++ setToolTip(CItemTreeWidget::eColumnName,filename + "\n" + getInfo()); ++ ++ QFile f(filename); ++ f.open(QIODevice::ReadOnly); ++ QCryptographicHash md5(QCryptographicHash::Md5); ++ md5.addData(f.read(1024)); ++ hash = md5.result().toHex(); ++ f.close(); ++} ++ ++void CItemMap::drawBoundingBox(QPainter& p, IDrawContext * dc) ++{ ++ QPointF pt1 = ref1; ++ QPointF pt2 = ref2; ++ QPointF pt3 = ref3; ++ QPointF pt4 = ref4; ++ ++ dc->convertCoord2Map(pt1); ++ dc->convertCoord2Map(pt2); ++ dc->convertCoord2Map(pt3); ++ dc->convertCoord2Map(pt4); ++ ++ dc->convertMap2Screen(pt1); ++ dc->convertMap2Screen(pt2); ++ dc->convertMap2Screen(pt3); ++ dc->convertMap2Screen(pt4); ++ ++ p.setPen(QPen(Qt::red, 2)); ++ QPolygonF line; ++ line << pt1 << pt2 << pt3 << pt4 << pt1; ++ p.drawPolyline(line); ++ ++} +diff --git a/src/qmaptool/items/CItemMap.h b/src/qmaptool/items/CItemMap.h +new file mode 100644 +index 00000000..b0b8ca84 +--- /dev/null ++++ b/src/qmaptool/items/CItemMap.h +@@ -0,0 +1,54 @@ ++/********************************************************************************************** ++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CITEMMAP_H ++#define CITEMMAP_H ++ ++#include "helpers/CGdalFile.h" ++#include "items/IItem.h" ++ ++#include ++ ++class GDALDataset; ++class CItemMapLayer; ++ ++class CItemMap : public CGdalFile, public IItem, public QTreeWidgetItem ++{ ++public: ++ CItemMap(const QString& filename); ++ virtual ~CItemMap(); ++ ++ void setupChanged() override {} ++ ++ QPointF getScale() const; ++ ++ const QString& getHash() const ++ { ++ return hash; ++ } ++ ++ void reload() override; ++ ++ void drawBoundingBox(QPainter& p, IDrawContext *dc); ++ ++private: ++ QString hash; ++}; ++ ++#endif //CITEMMAP_H ++ +diff --git a/src/qmaptool/items/CItemMapLayer.cpp b/src/qmaptool/items/CItemMapLayer.cpp +new file mode 100644 +index 00000000..a72a81a3 +--- /dev/null ++++ b/src/qmaptool/items/CItemMapLayer.cpp +@@ -0,0 +1,119 @@ ++/********************************************************************************************** ++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "canvas/CDrawContextProj.h" ++#include "CMainWindow.h" ++#include "items/CItemMap.h" ++#include "items/CItemMapLayer.h" ++#include "items/CItemTreeWidget.h" ++ ++#include ++ ++CItemMapLayer::CItemMapLayer(QTreeWidget *parent) ++ : IItem("") ++ , QTreeWidgetItem(parent) ++ , vrt(QDir::temp().absoluteFilePath("QMapTool_XXXXXX.vrt")) ++{ ++ drawContext = new CDrawContextProj(CMainWindow::self().getCanvas(), parent); ++ ++ setText(CItemTreeWidget::eColumnName, tr("Layer")); ++ setIcon(CItemTreeWidget::eColumnName, QIcon("://icons/32x32/MapLayer.png")); ++ ++ // this is needed to create a filename ++ vrt.open(); ++ vrt.close(); ++} ++ ++ ++const QString& CItemMapLayer::getProjection() const ++{ ++ return drawContext->getProjection(); ++} ++ ++bool CItemMapLayer::addMap(CItemMap *map) ++{ ++ const QPointF& mapScale = map->getScale(); ++ ++ const QTransform& trFwd = drawContext->getTrFwd(); ++ ++ if(trFwd.isScaling()) ++ { ++ if((qAbs((mapScale.x() - trFwd.m11())/trFwd.m11()) > 0.2) || (qAbs((mapScale.y() - trFwd.m22())/trFwd.m22()) > 0.2)) ++ { ++ return false; ++ } ++ } ++ ++ addChild(map); ++ updateLayer(); ++ ++ return drawContext->getIsValid(); ++} ++ ++void CItemMapLayer::updateLayer() ++{ ++ drawContext->unload(); ++ setToolTip(CItemTreeWidget::eColumnName, ""); ++ ++ const int N = childCount(); ++ if(N == 0) ++ { ++ return; ++ } ++ ++ QStringList args; ++ args << vrt.fileName(); ++ ++ for(int n = 0; n < N; n++) ++ { ++ CItemMap * map = dynamic_cast(child(n)); ++ if(map != nullptr) ++ { ++ args << map->getFilename(); ++ } ++ } ++ ++ QProcess proc; ++ proc.start(IAppSetup::self().getGdalbuildvrt(), args); ++ proc.waitForStarted(); ++ proc.waitForFinished(); ++ ++ drawContext->setSourceFile(vrt.fileName(), true); ++ setToolTip(CItemTreeWidget::eColumnName, drawContext->getInfo()); ++} ++ ++bool CItemMapLayer::drawFx(QPainter& p, CCanvas::redraw_e needsRedraw) ++{ ++ drawContext->draw(p, needsRedraw); ++ return true; ++} ++ ++void CItemMapLayer::drawBoundingBoxes(QPainter& p, IDrawContext * dc) ++{ ++ const int N = childCount(); ++ for(int n = 0; n < N; n++) ++ { ++ CItemMap * map = dynamic_cast(child(n)); ++ if(map == nullptr) ++ { ++ continue; ++ } ++ ++ map->drawBoundingBox(p, dc); ++ } ++} +diff --git a/src/qmaptool/items/CItemMapLayer.h b/src/qmaptool/items/CItemMapLayer.h +new file mode 100644 +index 00000000..1165c529 +--- /dev/null ++++ b/src/qmaptool/items/CItemMapLayer.h +@@ -0,0 +1,57 @@ ++/********************************************************************************************** ++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CITEMMAPLAYER_H ++#define CITEMMAPLAYER_H ++ ++#include "items/IItem.h" ++ ++#include ++#include ++#include ++ ++class CItemMap; ++class CDrawContextProj; ++ ++class CItemMapLayer : public IItem, public QTreeWidgetItem ++{ ++ Q_OBJECT ++public: ++ CItemMapLayer(QTreeWidget * parent); ++ virtual ~CItemMapLayer() = default; ++ ++ bool addMap(CItemMap * map); ++ ++ bool drawFx(QPainter& p, CCanvas::redraw_e needsRedraw) override; ++ ++ void drawBoundingBoxes(QPainter& p, IDrawContext *dc); ++ ++ void setupChanged() override {} ++ ++ const QString& getProjection() const; ++ ++protected: ++ friend bool sortByScale(QTreeWidgetItem * item1, QTreeWidgetItem * item2); ++ ++ void updateLayer(); ++ ++ QTemporaryFile vrt; ++}; ++ ++#endif //CITEMMAPLAYER_H ++ +diff --git a/src/qmaptool/items/CItemRefMap.cpp b/src/qmaptool/items/CItemRefMap.cpp +new file mode 100644 +index 00000000..1bbcad76 +--- /dev/null ++++ b/src/qmaptool/items/CItemRefMap.cpp +@@ -0,0 +1,114 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "items/CItemRefMap.h" ++#include "overlay/COverlayRefMap.h" ++#include "overlay/refmap/COverlayRefMapPoint.h" ++ ++#include ++ ++CItemRefMap::CItemRefMap(const QString &filename, QStackedWidget *stackedWidget, QListWidget *parent) ++ : CItemFile(filename, parent) ++{ ++ overlay = new COverlayRefMap(this, stackedWidget); ++ connect(overlay, &COverlayRefMap::sigChanged, this, &CItemRefMap::sigChanged); ++} ++ ++CItemRefMap::~CItemRefMap() ++{ ++ overlay->deleteLater(); ++} ++ ++void CItemRefMap::saveSettings(QSettings& cfg) ++{ ++ CItemFile::saveSettings(cfg); ++ overlay->saveSettings(cfg); ++} ++ ++void CItemRefMap::loadSettings(QSettings& cfg) ++{ ++ CItemFile::loadSettings(cfg); ++ overlay->loadSettings(cfg); ++} ++ ++void CItemRefMap::addRefPoints(QList& points) ++{ ++ overlay->addRefPoints(points); ++} ++ ++QString CItemRefMap::getMapProjection() const ++{ ++ return overlay->getMapProjection(); ++} ++ ++const QList CItemRefMap::getRefPoints() const ++{ ++ return overlay->getRefPoints(); ++} ++ ++ ++void CItemRefMap::toFront() ++{ ++ overlay->toFront(); ++} ++ ++bool CItemRefMap::drawFx(QPainter& p, CCanvas::redraw_e needsRedraw) ++{ ++ CItemFile::drawFx(p, needsRedraw); ++ overlay->drawFx(p, needsRedraw); ++ return true; ++} ++ ++void CItemRefMap::mouseMoveEventFx(QMouseEvent *e) ++{ ++ CItemFile::mouseMoveEventFx(e); ++ if(!mapIsMoving) ++ { ++ overlay->mouseMoveEventFx(e); ++ } ++} ++ ++void CItemRefMap::mouseReleaseEventFx(QMouseEvent *e) ++{ ++ if(!mapDidMove) ++ { ++ overlay->mouseReleaseEventFx(e); ++ } ++ CItemFile::mouseReleaseEventFx(e); ++} ++ ++bool CItemRefMap::keyPressEventFx(QKeyEvent *e) ++{ ++ return overlay->keyPressEventFx(e); ++} ++ ++void CItemRefMap::leaveEventFx(QEvent *e) ++{ ++ CItemFile::leaveEventFx(e); ++ overlay->abortStep(); ++} ++ ++QCursor CItemRefMap::getCursorFx() ++{ ++ return overlay->getCursorFx(); ++} ++ ++bool CItemRefMap::isOk() const ++{ ++ return overlay->isOk(); ++} +diff --git a/src/qmaptool/items/CItemRefMap.h b/src/qmaptool/items/CItemRefMap.h +new file mode 100644 +index 00000000..5e74e8bf +--- /dev/null ++++ b/src/qmaptool/items/CItemRefMap.h +@@ -0,0 +1,56 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CITEMREFMAP_H ++#define CITEMREFMAP_H ++ ++#include "items/CItemFile.h" ++ ++class COverlayRefMap; ++class COverlayRefMapPoint; ++ ++class CItemRefMap : public CItemFile ++{ ++public: ++ CItemRefMap(const QString& filename, QStackedWidget * stackedWidget, QListWidget *parent); ++ virtual ~CItemRefMap(); ++ ++ void saveSettings(QSettings& cfg) override; ++ void loadSettings(QSettings& cfg) override; ++ ++ void addRefPoints(QList &points); ++ QString getMapProjection() const; ++ const QList getRefPoints() const; ++ ++ void toFront() override; ++ ++ bool drawFx(QPainter& p, CCanvas::redraw_e needsRedraw) override; ++ void mouseMoveEventFx(QMouseEvent *e) override; ++ void mouseReleaseEventFx(QMouseEvent *e) override; ++ void leaveEventFx(QEvent *e) override; ++ bool keyPressEventFx(QKeyEvent *e) override; ++ QCursor getCursorFx() override; ++ ++ bool isOk() const override; ++ ++private: ++ COverlayRefMap * overlay; ++}; ++ ++#endif //CITEMREFMAP_H ++ +diff --git a/src/qmaptool/items/CItemTreeWidget.cpp b/src/qmaptool/items/CItemTreeWidget.cpp +new file mode 100644 +index 00000000..9a68beaf +--- /dev/null ++++ b/src/qmaptool/items/CItemTreeWidget.cpp +@@ -0,0 +1,317 @@ ++/********************************************************************************************** ++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "canvas/CDrawContextProj.h" ++#include "helpers/CDraw.h" ++#include "helpers/CSettings.h" ++#include "items/CItemMap.h" ++#include "items/CItemMapLayer.h" ++#include "items/CItemTreeWidget.h" ++ ++#include ++ ++CItemTreeWidget::CItemTreeWidget(QWidget *parent) ++ : QWidget(parent) ++{ ++ setupUi(this); ++ ++ connect(toolFiles, &QToolButton::clicked, this, &CItemTreeWidget::slotFiles); ++ connect(toolDelFile, &QToolButton::clicked, this, &CItemTreeWidget::slotDeleteFile); ++ connect(toolDelFiles, &QToolButton::clicked, this, &CItemTreeWidget::slotDeleteFiles); ++ connect(treeFiles, &QTreeWidget::itemSelectionChanged, this, &CItemTreeWidget::slotSelectionChanged); ++} ++ ++void CItemTreeWidget::saveSettings(QSettings& cfg) ++{ ++ QStringList files; ++ const int N = treeFiles->topLevelItemCount(); ++ for(int n = 0; n < N; n++) ++ { ++ CItemMapLayer * layer = dynamic_cast(treeFiles->topLevelItem(n)); ++ if(layer == nullptr) ++ { ++ continue; ++ } ++ ++ const int M = layer->childCount(); ++ for(int m = 0; m < M; m++) ++ { ++ CItemMap * map = dynamic_cast(layer->child(m)); ++ if(map != nullptr) ++ { ++ files << map->getFilename(); ++ cfg.beginGroup(QString("%1_%2").arg(n).arg(m)); ++ map->saveSettings(cfg); ++ cfg.endGroup(); ++ } ++ } ++ } ++ ++ cfg.setValue("files", files); ++} ++ ++void CItemTreeWidget::loadSettings(QSettings& cfg) ++{ ++ QStringList files = cfg.value("files", QStringList()).toStringList(); ++ addFiles(files); ++ ++ const int N = treeFiles->topLevelItemCount(); ++ for(int n = 0; n < N; n++) ++ { ++ CItemMapLayer * layer = dynamic_cast(treeFiles->topLevelItem(n)); ++ if(layer == nullptr) ++ { ++ continue; ++ } ++ ++ const int M = layer->childCount(); ++ for(int m = 0; m < M; m++) ++ { ++ CItemMap * map = dynamic_cast(layer->child(m)); ++ if(map != nullptr) ++ { ++ cfg.beginGroup(QString("%1_%2").arg(n).arg(m)); ++ map->loadSettings(cfg); ++ cfg.endGroup(); ++ } ++ } ++ } ++} ++ ++ITool * CItemTreeWidget::currentItem() ++{ ++ CItemMapLayer * layer = dynamic_cast(treeFiles->currentItem()); ++ if(layer != nullptr) ++ { ++ return layer; ++ } ++ ++ CItemMap * map = dynamic_cast(treeFiles->currentItem()); ++ if(map != nullptr) ++ { ++ return dynamic_cast(map->QTreeWidgetItem::parent()); ++ } ++ ++ return nullptr; ++} ++ ++bool sortByScale(QTreeWidgetItem * item1, QTreeWidgetItem * item2) ++{ ++ CItemMapLayer * layer1 = dynamic_cast(item1); ++ CItemMapLayer * layer2 = dynamic_cast(item2); ++ if(layer1 == nullptr || layer2 == nullptr) ++ { ++ return false; ++ } ++ ++ return layer1->drawContext->getTrFwd().m11() < layer2->drawContext->getTrFwd().m11(); ++} ++ ++ ++void CItemTreeWidget::addFiles(const QStringList& files) ++{ ++ QString projstr; ++ ++ // preset projstr if there is already a layer with a projection. ++ if(treeFiles->topLevelItemCount() != 0) ++ { ++ CItemMapLayer * layer = dynamic_cast(treeFiles->topLevelItem(0)); ++ if(layer != nullptr) ++ { ++ projstr = layer->getProjection(); ++ } ++ } ++ ++ ++ for(const QString& file : files) ++ { ++ CItemMap * map = new CItemMap(file); ++ ++ // if something failed simply go on. ++ if(!map->getIsValid()) ++ { ++ delete map; ++ continue; ++ } ++ ++ // setup/test for common projection ++ if(projstr.isEmpty()) ++ { ++ projstr = map->getProjection(); ++ } ++ else if(map->getProjection() != projstr) ++ { ++ const QString msg = tr("

The current map '%1' does not match the projection of previous loaded maps. " ++ "All map files need to have the same projection.

" ++ "

This file: %2

" ++ "

Expected: %3

" ++ ).arg(file).arg(map->getProjection()).arg(projstr); ++ QMessageBox::warning(this, tr("Error..."), msg, QMessageBox::Abort); ++ delete map; ++ continue; ++ } ++ ++ // if the map is already in the list simply go on ++ if(findMapByHash(map->getHash()) != nullptr) ++ { ++ delete map; ++ continue; ++ } ++ ++ CItemMapLayer * layer = nullptr; ++ const int N = treeFiles->topLevelItemCount(); ++ for(int n = 0; n < N; n++) ++ { ++ layer = dynamic_cast(treeFiles->topLevelItem(n)); ++ if(layer == nullptr) ++ { ++ continue; ++ } ++ ++ if(layer->addMap(map)) ++ { ++ break; ++ } ++ layer = nullptr; ++ } ++ ++ if(layer == nullptr) ++ { ++ layer = new CItemMapLayer(treeFiles); ++ layer->addMap(map); ++ } ++ } // for(const QString& file : files) ++ ++ sort(sortByScale); ++ treeFiles->expandAll(); ++ slotSelectionChanged(); ++} ++ ++CItemMap * CItemTreeWidget::findMapByHash(const QString& hash) ++{ ++ const int N = treeFiles->topLevelItemCount(); ++ for(int n = 0; n < N; n++) ++ { ++ CItemMapLayer * layer = dynamic_cast(treeFiles->topLevelItem(n)); ++ if(layer == nullptr) ++ { ++ continue; ++ } ++ ++ const int M = layer->childCount(); ++ for(int m = 0; m < M; m++) ++ { ++ CItemMap * map = dynamic_cast(layer->child(m)); ++ if((map != nullptr) && (map->getHash() == hash)) ++ { ++ return map; ++ } ++ } ++ } ++ ++ return nullptr; ++} ++ ++void CItemTreeWidget::slotFiles() ++{ ++ SETTINGS; ++ QString path = cfg.value("Path/mapInput", QDir::homePath()).toString(); ++ ++ const QStringList& files = QFileDialog::getOpenFileNames(this, tr("Select files..."), path); ++ if(files.isEmpty()) ++ { ++ return; ++ } ++ ++ cfg.setValue("Path/mapInput", QFileInfo(files.first()).absolutePath()); ++ addFiles(files); ++} ++ ++void CItemTreeWidget::slotDeleteFiles() ++{ ++ treeFiles->clear(); ++ slotSelectionChanged(); ++} ++ ++void CItemTreeWidget::slotDeleteFile() ++{ ++ CItemMap * map = dynamic_cast(treeFiles->currentItem()); ++ if(map != nullptr) ++ { ++ QTreeWidgetItem * layer = map->QTreeWidgetItem::parent(); ++ delete map; ++ if(layer->childCount() == 0) ++ { ++ delete layer; ++ } ++ slotSelectionChanged(); ++ return; ++ } ++ ++ CItemMapLayer * layer = dynamic_cast(treeFiles->currentItem()); ++ if(layer != nullptr) ++ { ++ delete layer; ++ slotSelectionChanged(); ++ return; ++ } ++} ++ ++void CItemTreeWidget::slotSelectionChanged() ++{ ++ bool isNotEmpty = treeFiles->topLevelItemCount() != 0; ++ bool isSelected = !treeFiles->selectedItems().isEmpty(); ++ ++ toolDelFile->setEnabled(isSelected); ++ toolDelFiles->setEnabled(isNotEmpty); ++ toolReloadFile->setEnabled(isSelected); ++ ++ emit sigSelectionChanged(); ++} ++ ++bool CItemTreeWidget::drawFx(QPainter& p, CCanvas::redraw_e needsRedraw) ++{ ++ bool res = false; ++ ++ CItemMapLayer * layer = dynamic_cast(currentItem()); ++ if(layer != nullptr) ++ { ++ res = layer->drawFx(p, needsRedraw); ++ ++ IDrawContext * dc = layer->getDrawContext(); ++ ++ if(dc == nullptr) ++ { ++ return res; ++ } ++ ++ const int N = treeFiles->topLevelItemCount(); ++ for(int n = 0; n < N; n++) ++ { ++ CItemMapLayer * layer = dynamic_cast(treeFiles->topLevelItem(n)); ++ if(layer == nullptr) ++ { ++ continue; ++ } ++ ++ layer->drawBoundingBoxes(p, dc); ++ } ++ } ++ ++ return res; ++} +diff --git a/src/qmaptool/items/CItemTreeWidget.h b/src/qmaptool/items/CItemTreeWidget.h +new file mode 100644 +index 00000000..25d87935 +--- /dev/null ++++ b/src/qmaptool/items/CItemTreeWidget.h +@@ -0,0 +1,94 @@ ++/********************************************************************************************** ++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CITEMTREEWIDGET_H ++#define CITEMTREEWIDGET_H ++ ++#include "ui_IItemTreeWidget.h" ++ ++class QSettings; ++class ITool; ++class CItemMap; ++ ++class CItemTreeWidget : public QWidget, private Ui::IItemTreeWidget ++{ ++ Q_OBJECT ++public: ++ enum column_e ++ { ++ eColumnName ++ }; ++ ++ CItemTreeWidget(QWidget * parent); ++ virtual ~CItemTreeWidget() = default; ++ ++ void saveSettings(QSettings& cfg); ++ void loadSettings(QSettings& cfg); ++ ++ ITool *currentItem(); ++ ++ template< typename LessThan> ++ void sort(LessThan lessThan) ++ { ++ treeFiles->blockSignals(true); ++ ++ QList items; ++ while(treeFiles->topLevelItemCount() != 0) ++ { ++ items << treeFiles->takeTopLevelItem(0); ++ } ++ ++ qSort(items.begin(), items.end(), lessThan); ++ ++ for(QTreeWidgetItem* item : items) ++ { ++ treeFiles->addTopLevelItem(item); ++ } ++ ++ treeFiles->blockSignals(false); ++ } ++ ++ qint32 topLevelItemCount() const ++ { ++ return treeFiles->topLevelItemCount(); ++ } ++ ++ QTreeWidgetItem * topLevelItem(int n) ++ { ++ return treeFiles->topLevelItem(n); ++ } ++ ++ bool drawFx(QPainter& p, CCanvas::redraw_e needsRedraw); ++ ++signals: ++ void sigSelectionChanged(); ++ void sigChanged(); ++ ++protected slots: ++ void slotFiles(); ++ void slotDeleteFiles(); ++ void slotDeleteFile(); ++ void slotSelectionChanged(); ++ ++protected: ++ void addFiles(const QStringList& files); ++ CItemMap *findMapByHash(const QString& hash); ++}; ++ ++#endif //CITEMTREEWIDGET_H ++ +diff --git a/src/qmaptool/items/IItem.cpp b/src/qmaptool/items/IItem.cpp +new file mode 100644 +index 00000000..9e8e636f +--- /dev/null ++++ b/src/qmaptool/items/IItem.cpp +@@ -0,0 +1,141 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "canvas/IDrawContext.h" ++#include "CMainWindow.h" ++#include "items/IItem.h" ++ ++#include ++ ++IItem::IItem(const QString &filename) ++ : filename(filename) ++{ ++} ++ ++void IItem::saveSettings(QSettings& cfg) ++{ ++ if(nullptr != drawContext) ++ { ++ drawContext->saveSettings(cfg); ++ } ++} ++ ++void IItem::loadSettings(QSettings& cfg) ++{ ++ if(nullptr != drawContext) ++ { ++ drawContext->loadSettings(cfg); ++ } ++} ++ ++void IItem::reload() ++{ ++ if(nullptr == drawContext) ++ { ++ return; ++ } ++ drawContext->setSourceFile(filename, false); ++} ++ ++bool IItem::drawFx(QPainter& p, CCanvas::redraw_e needsRedraw) ++{ ++ if(nullptr == drawContext) ++ { ++ return false; ++ } ++ ++ drawContext->draw(p, needsRedraw); ++ return true; ++} ++ ++void IItem::mousePressEventFx(QMouseEvent *e) ++{ ++ if(nullptr == drawContext) ++ { ++ return; ++ } ++ ++ if(e->button() == Qt::LeftButton) ++ { ++ lastPos = e->pos(); ++ firstPos = lastPos; ++ mapIsMoving = true; ++ mapDidMove = false; ++ } ++} ++ ++void IItem::mouseMoveEventFx(QMouseEvent *e) ++{ ++ if(nullptr == drawContext) ++ { ++ return; ++ } ++ ++ const QPoint& point = e->pos(); ++ if(mapIsMoving) ++ { ++ if((point - firstPos).manhattanLength() >= 4) ++ { ++ drawContext->move(point - lastPos); ++ ++ lastPos = point; ++ mapDidMove = true; ++ ++ drawContext->triggerCompleteUpdate(CCanvas::eRedrawMap); ++ } ++ } ++} ++ ++void IItem::mouseReleaseEventFx(QMouseEvent *e) ++{ ++ if(nullptr == drawContext) ++ { ++ return; ++ } ++ ++ if(e->button() == Qt::LeftButton) ++ { ++ lastPos = e->pos(); ++ mapIsMoving = false; ++ mapDidMove = false; ++ } ++} ++ ++void IItem::wheelEventFx(QWheelEvent *e) ++{ ++ if(nullptr == drawContext) ++ { ++ return; ++ } ++ ++ // angleDelta() returns the eighths of a degree ++ // of the mousewheel ++ // -> zoom in/out every 15 degress = every 120 eights ++ const int EIGHTS_ZOOM = 15 * 8; ++ zoomAngleDelta += e->angleDelta().y(); ++ if(abs(zoomAngleDelta) < EIGHTS_ZOOM) ++ { ++ return; ++ } ++ ++ zoomAngleDelta = 0; ++ ++ drawContext->zoom(CMainWindow::self().flipMouseWheel() ? (e->delta() < 0) : (e->delta() > 0), e->posF()); ++ drawContext->triggerCompleteUpdate(CCanvas::eRedrawAll); ++} ++ +diff --git a/src/qmaptool/items/IItem.h b/src/qmaptool/items/IItem.h +new file mode 100644 +index 00000000..59697d2c +--- /dev/null ++++ b/src/qmaptool/items/IItem.h +@@ -0,0 +1,97 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef IITEM_H ++#define IITEM_H ++ ++ ++#include "tool/ITool.h" ++#include ++ ++class QSettings; ++class IDrawContext; ++ ++class IItem : public QObject, public ITool ++{ ++ Q_OBJECT ++public: ++ IItem(const QString& filename); ++ virtual ~IItem() = default; ++ ++ virtual void saveSettings(QSettings& cfg); ++ virtual void loadSettings(QSettings& cfg); ++ ++ const QString& getFilename() const ++ { ++ return filename; ++ } ++ ++ IDrawContext* getDrawContext() const ++ { ++ return drawContext; ++ } ++ ++ bool getMapDidMove() const ++ { ++ return mapDidMove; ++ } ++ ++ bool getMapIsMoving() const ++ { ++ return mapIsMoving; ++ } ++ ++ /// reload file into draw context ++ virtual void reload(); ++ /// item has been selected, bring everything to front (to be displayed) ++ virtual void toFront(){} ++ ++ bool drawFx(QPainter& p, CCanvas::redraw_e needsRedraw) override; ++ void mousePressEventFx(QMouseEvent *e) override; ++ void mouseMoveEventFx(QMouseEvent *e) override; ++ void mouseReleaseEventFx(QMouseEvent *e) override; ++ void wheelEventFx(QWheelEvent *e) override; ++ ++ virtual bool isOk() const ++ { ++ return false; ++ } ++ ++signals: ++ void sigChanged(); ++ ++protected: ++ QString filename; ++ IDrawContext * drawContext = nullptr; ++ ++ /// true while left mouse button is pressed down ++ bool mapIsMoving = false; ++ /// true if map actually moved, if not it's a single click ++ bool mapDidMove = false; ++ ++ /// last mouse position ++ QPoint lastPos; ++ /// mouse position when left button was pressed ++ QPoint firstPos; ++ ++ /// current accumulated angleDelta, used/required for zooming on track pads ++ int zoomAngleDelta = 0; ++}; ++ ++#endif //IITEM_H ++ +diff --git a/src/qmaptool/items/IItemListWidget.ui b/src/qmaptool/items/IItemListWidget.ui +new file mode 100644 +index 00000000..ae057f1a +--- /dev/null ++++ b/src/qmaptool/items/IItemListWidget.ui +@@ -0,0 +1,127 @@ ++ ++ ++ IItemListWidget ++ ++ ++ ++ 0 ++ 0 ++ 258 ++ 152 ++ ++ ++ ++ Form ++ ++ ++ ++ 3 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ ++ ++ 3 ++ ++ ++ ++ ++ Add map files to list ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/PathBlue.png:/icons/32x32/PathBlue.png ++ ++ ++ ++ ++ ++ ++ false ++ ++ ++ Remove selected file from the list. ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/DeleteOne.png:/icons/32x32/DeleteOne.png ++ ++ ++ ++ ++ ++ ++ false ++ ++ ++ Clear complete list of map files. ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/DeleteMultiple.png:/icons/32x32/DeleteMultiple.png ++ ++ ++ ++ ++ ++ ++ false ++ ++ ++ Reload the currently selected map. ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/Reload.png:/icons/32x32/Reload.png ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ 40 ++ 20 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/src/qmaptool/items/IItemTreeWidget.ui b/src/qmaptool/items/IItemTreeWidget.ui +new file mode 100644 +index 00000000..cbe6fd8e +--- /dev/null ++++ b/src/qmaptool/items/IItemTreeWidget.ui +@@ -0,0 +1,135 @@ ++ ++ ++ IItemTreeWidget ++ ++ ++ ++ 0 ++ 0 ++ 258 ++ 152 ++ ++ ++ ++ Form ++ ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ ++ ++ 3 ++ ++ ++ ++ ++ Add map files to list ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/PathBlue.png:/icons/32x32/PathBlue.png ++ ++ ++ ++ ++ ++ ++ false ++ ++ ++ Remove selected file from the list. ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/DeleteOne.png:/icons/32x32/DeleteOne.png ++ ++ ++ ++ ++ ++ ++ false ++ ++ ++ Clear complete list of map files. ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/DeleteMultiple.png:/icons/32x32/DeleteMultiple.png ++ ++ ++ ++ ++ ++ ++ false ++ ++ ++ Reload the currently selected map. ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/Reload.png:/icons/32x32/Reload.png ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ 40 ++ 20 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ false ++ ++ ++ ++ 1 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/src/qmaptool/locale/qmaptool.ts b/src/qmaptool/locale/qmaptool.ts +new file mode 100644 +index 00000000..025b1390 +--- /dev/null ++++ b/src/qmaptool/locale/qmaptool.ts +@@ -0,0 +1,1675 @@ ++ ++ ++ ++ ++ CCanvas ++ ++ ++ No map view available. ++ ++ ++ ++ ++ CCommandProcessor ++ ++ ++ Print debug output to console. ++ ++ ++ ++ ++ Print debug output to logfile (temp. path). ++ ++ ++ ++ ++ Do not show splash screen. ++ ++ ++ ++ ++ File with QMapTool configuration. ++ ++ ++ ++ ++ file ++ ++ ++ ++ ++ CDialogRefPoint ++ ++ ++ bad coordinate ++ ++ ++ ++ ++ ++ Error ++ ++ ++ ++ ++ Bad value for X pixel. ++ ++ ++ ++ ++ Bad value for Y pixel. ++ ++ ++ ++ ++ CDrawContextPixel ++ ++ ++ Failed to load ++ ++ ++ ++ ++ CGdalFile ++ ++ ++ ++ ++ Error... ++ ++ ++ ++ ++ ++ Failed to load file: %1 ++ ++ ++ ++ ++ File must be 8 bit palette or gray indexed. ++ ++ ++ ++ ++ (color table) ++ ++ ++ ++ ++ (RGB) ++ ++ ++ ++ ++ (RGBA) ++ ++ ++ ++ ++ (unknown) ++ ++ ++ ++ ++ CGridPlacer ++ ++ ++ Select one of the corners and place the marker at the corresponding grid crossing on the map. All 4 corners have to be placed. ++ ++ ++ ++ ++ Point 1 - not set ++ ++ ++ ++ ++ Point 1 - ok ++ ++ ++ ++ ++ ++ Point 1 - bad ++ ++ ++ ++ ++ Point 2 - ok ++ ++ ++ ++ ++ ++ Point 2 - bad ++ ++ ++ ++ ++ Point 3 - ok ++ ++ ++ ++ ++ ++ Point 3 - bad ++ ++ ++ ++ ++ Point 4 - ok ++ ++ ++ ++ ++ ++ Point 4 - bad ++ ++ ++ ++ ++ Point 2 - not set ++ ++ ++ ++ ++ Point 3 - not set ++ ++ ++ ++ ++ Point 4 - not set ++ ++ ++ ++ ++ CGridSelArea ++ ++ ++ Select the area to be covered by the calculated reference points. Simply grab the corners of the selection rectangle with a left click and place them where you want with a second click. ++ ++ ++ ++ ++ CGridSetRef ++ ++ ++ Valid coordinate formats: If the projection is lat/lon all values have to be in degree, e.g. "48.2" or "12.4". For all other projections values are either in multiple of meter or feet. If you are doing it wrong the entry field will turn red. ++ ++ ++ ++ ++ CItemListWidget ++ ++ ++ Select files... ++ ++ ++ ++ ++ COverlayCutMap ++ ++ ++ Delete mask... ++ ++ ++ ++ ++ Are you sure to delete complete mask? ++ ++ ++ ++ ++ Save mask... ++ ++ ++ ++ ++ Load mask... ++ ++ ++ ++ ++ Failed... ++ ++ ++ ++ ++ Not a shape file. ++ ++ ++ ++ ++ COverlayGridTool ++ ++ ++ Before you proceed with 'ok': ++Please cross check all data once again. A bad reference coordinate will ruin all the work. Also cross check if the selected area contains as many reference points as possible at the border. You can easily delete points outside the map in the Reference Tool. But it's much more effort to set additional points in case you miss some. When you are done press 'ok' to transfer the derived reference points to the Reference Tool. ++ ++The next step will be to use the Reference Tool to adjust the position of all reference points to the real grid position on the map. ++ ++ ++ ++ ++ COverlayRefMap ++ ++ ++ If you used the Grid Tool you have to fine tune the reference points by placing them as much as possible on the grid crossing. Be aware that if you over scale you get jumping points by rounding effects. Be precise but do not make religion out of the task. ++If your mouse focus is on the map you can use the N and B keys to jump forward an backward in the reference point list. ++The is also the option to fine tune the reference points in auto-mode. In this mode the next reference point is selected automatically right after you placed the current one. This is very convenient for a large number of reference points. ++ ++ ++ ++ ++ Save reference points... ++ ++ ++ ++ ++ Load reference points... ++ ++ ++ ++ ++ Delete all reference points... ++ ++ ++ ++ ++ Are you sure to delete all reference points in the list? ++ ++ ++ ++ ++ Delete... ++ ++ ++ ++ ++ Delete all selected reference points? ++ ++ ++ ++ ++ COverlayRefMapPoint ++ ++ ++ bad coordinate ++ ++ ++ ++ ++ CProjWizard ++ ++ ++ north ++ ++ ++ ++ ++ south ++ ++ ++ ++ ++ Error... ++ ++ ++ ++ ++ The value ++'%1' ++is not a valid coordinate system definition: ++%2 ++ ++ ++ ++ ++ CSetupExtTools ++ ++ ++ ++ ++ ++ ++ ++ <b style='color: red;'>not found</b> ++ ++ ++ ++ ++ Select %1 binary... ++ ++ ++ ++ ++ CShell ++ ++ ++ Execution of external program `%1` failed: ++ ++ ++ ++ ++ Process cannot be started. ++ ++ ++ ++ ++ ++ Make sure the required packages are installed, `%1` exists and is executable. ++ ++ ++ ++ ++ ++ External process crashed. ++ ++ ++ ++ ++ ++ An unknown error occurred. ++ ++ ++ ++ ++ ++ !!! failed !!! ++ ++ ++ ++ ++ ++ ++Canceled by user's request. ++ ++ ++ ++ ++ ++ !!! done !!! ++ ++ ++ ++ ++ ++ CToolAddOverview ++ ++ ++ Add Overviews ++ ++ ++ ++ ++ Raster map files consume quite some memory if a larger area is displayed. Pre-calculated overview levels help to speed up loading and displaying the map. These overviews can be stored within the map file as well as an external file. GDAL can remove internally stored overviews, however it will not free the used space in the file. Therefore it's size will remain large. If you do not like that use the external option. ++ ++ ++ ++ ++ CToolCutMap ++ ++ ++ Cut Map ++ ++ ++ ++ ++ Paper maps usually have a border you don't want to have. To combine maps seamlessly you have to cut that border, replacing it by transparent pixel. This tool allows you to define a cut line and it will add an alpha channel for transparency to your map. ++ ++ ++ ++ ++ CToolExport ++ ++ ++ Export Maps ++ ++ ++ ++ ++ To use the maps on your device you have to export them to the proprietary format supported by the device. Depending on the device this can vary from a single layer map to a map stack with maps of different scale. ++ ++ ++ ++ ++ Note: This tool will use all files in the list as a input. This will only work if all files have the same projection. ++ ++ ++ ++ ++ Select filename... ++ ++ ++ ++ ++ CToolGrid ++ ++ ++ By placing 4 reference points at the corners of a grid square and referencing them by their top left corner, the width and height, all the other grid points can be estimated. ++ ++ ++ ++ ++ CToolPalettize ++ ++ ++ Add Color Palette ++ ++ ++ ++ ++ Usually you use RGBA color while referencing a map because the large color space allows you to scale and rotate the map without any loss of quality. But it results into rather large files. The file size can be optimized by using a color palette instead of the RGBA color space. The impact on quality is low as long as you do not want to scale or rotate the map. If you want to combine files with a color palette all files need to have the same palette. ++ ++ ++ ++ ++ Note: This tool will use all files in the list as a combined input to derive an optimal palette. This will only work if all files have the same projection and scale. ++ ++ ++ ++ ++ Select filename... ++ ++ ++ ++ ++ CToolRefMap ++ ++ ++ Reference Map ++ ++ ++ ++ ++ A scan of a paper map can be converted to a referenced raster map if you place at least three reference points on the map. The more points the better the result. If your map has a grid you can place points on that grid with the grid tool. ++ ++ ++ ++ ++ IAbout ++ ++ ++ About... ++ ++ ++ ++ ++ <b>QMapTool</b>, Version ++ ++ ++ ++ ++ ++ ++ ++ TextLabel ++ ++ ++ ++ ++ Qt ++ ++ ++ ++ ++ GDAL ++ ++ ++ ++ ++ Proj4 ++ ++ ++ ++ ++ This software is licensed under GPL3 or any later version ++ ++ ++ ++ ++ © 2017 Oliver Eichler (oliver.eichler@gmx.de) ++ ++ ++ ++ ++ ICoordFormatSetup ++ ++ ++ Coordinate Format... ++ ++ ++ ++ ++ N48° 53' 39.6" E13° 31' 6.78" ++ ++ ++ ++ ++ N48.8943° E013.51855° ++ ++ ++ ++ ++ N48° 53.660 E013° 31.113 ++ ++ ++ ++ ++ <b>Note:</b> For some GUI elements changing the units will not take effect until you restart QMapTool. ++ ++ ++ ++ ++ IDialogRefPoint ++ ++ ++ Dialog ++ ++ ++ ++ ++ Coord. Map File [pixel] ++ ++ ++ ++ ++ x ++ ++ ++ ++ ++ y ++ ++ ++ ++ ++ Coord. lat/lon WGS84 [°] ++ ++ ++ ++ ++ Bad position format. Must be: ++"[N|S] ddd mm.sss [W|E] ddd mm.sss" ++or ++"[N|S] ddd.ddd [W|E] ddd.ddd" ++ ++ ++ ++ ++ IGridPlacer ++ ++ ++ Form ++ ++ ++ ++ ++ Reset ++ ++ ++ ++ ++ Set Area ++ ++ ++ ++ ++ IGridSelArea ++ ++ ++ Form ++ ++ ++ ++ ++ TextLabel ++ ++ ++ ++ ++ IGridSetRef ++ ++ ++ Form ++ ++ ++ ++ ++ Grid Projection: ++ ++ ++ ++ ++ ... ++ ++ ++ ++ ++ TextLabel ++ ++ ++ ++ ++ Easting ++ ++ ++ ++ ++ Horiz. Spacing ++ ++ ++ ++ ++ Northing ++ ++ ++ ++ ++ Vert. Spacing ++ ++ ++ ++ ++ IItemListWidget ++ ++ ++ Form ++ ++ ++ ++ ++ Add map files to list ++ ++ ++ ++ ++ ++ ++ ++ ... ++ ++ ++ ++ ++ Remove selected file from the list. ++ ++ ++ ++ ++ Clear complete list of map files. ++ ++ ++ ++ ++ Reload the currently selected map. ++ ++ ++ ++ ++ IMainWindow ++ ++ ++ MainWindow ++ ++ ++ ++ ++ Setup ++ ++ ++ ++ ++ View ++ ++ ++ ++ ++ Window ++ ++ ++ ++ ++ ? ++ ++ ++ ++ ++ Tools ++ ++ ++ ++ ++ Shell ++ ++ ++ ++ ++ About ++ ++ ++ ++ ++ Ext. Tools ++ ++ ++ ++ ++ Setup paths to external tools, like gdalwarp etc. ++ ++ ++ ++ ++ ++ Flip Mouse Wheel ++ ++ ++ ++ ++ ++ Setup Units ++ ++ ++ ++ ++ Setup Coord. Format ++ ++ ++ ++ ++ Change the format coordinates are displayed ++ ++ ++ ++ ++ Show Tool Help ++ ++ ++ ++ ++ IOverlayCutMap ++ ++ ++ Form ++ ++ ++ ++ ++ Just move the map and zoom. ++ ++ ++ ++ ++ Add point to mask. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ... ++ ++ ++ ++ ++ Move point of mask. ++ ++ ++ ++ ++ Remove point from mask. ++ ++ ++ ++ ++ Remove complete cut mask. ++ ++ ++ ++ ++ Load cut mask from shape file. ++ ++ ++ ++ ++ Save cut mask to shape file. ++ ++ ++ ++ ++ IOverlayGridTool ++ ++ ++ Form ++ ++ ++ ++ ++ do not translate ++ ++ ++ ++ ++ IOverlayRefMap ++ ++ ++ Form ++ ++ ++ ++ ++ Just move the map and zoom. ++ ++ ++ ++ ++ Add reference point. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ... ++ ++ ++ ++ ++ Move reference point. ++ ++ ++ ++ ++ Remove single reference point. ++ ++ ++ ++ ++ Move reference points with auto mode. This will pickup the next point after you moved a reference point. ++ ++ ++ ++ ++ Remove all reference points. ++ ++ ++ ++ ++ Switch to the Grid Tool. ++ ++ ++ ++ ++ Load reference points from GCP file. ++ ++ ++ ++ ++ Save reference points into GCP file. ++ ++ ++ ++ ++ Sort list of reference points. ++ ++ ++ ++ ++ (x, y)[pixel] ++ ++ ++ ++ ++ (lat, lon)[°] ++ ++ ++ ++ ++ TextLabel ++ ++ ++ ++ ++ Final Map Projection: ++ ++ ++ ++ ++ Enter a valid projection string. Valid strings are "+proj..." or "+init=epsg:...". ++ ++ ++ ++ ++ Start projection wizard. ++ ++ ++ ++ ++ Delete ++ ++ ++ ++ ++ IProjWizard ++ ++ ++ Proj4 Wizard ++ ++ ++ ++ ++ Mercator ++ ++ ++ ++ ++ UTM ++ ++ ++ ++ ++ zone ++ ++ ++ ++ ++ user defined ++ ++ ++ ++ ++ Datum ++ ++ ++ ++ ++ World Mercator (OSM) ++ ++ ++ ++ ++ Result: ++ ++ ++ ++ ++ UPS North (North Pole) ++ ++ ++ ++ ++ UPS South (South Pole) ++ ++ ++ ++ ++ Projection ++ ++ ++ ++ ++ ISetupExtTools ++ ++ ++ Setup Ext. Tools ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ <b style='color: red;'>not found</b> ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ... ++ ++ ++ ++ ++ gdal_translate: ++ ++ ++ ++ ++ gdalbuildvrt ++ ++ ++ ++ ++ gdaladdo: ++ ++ ++ ++ ++ gdalwarp: ++ ++ ++ ++ ++ ++ ++ ++ ++ Setup user defined path. ++ ++ ++ ++ ++ qmt_rgb2pct ++ ++ ++ ++ ++ ++ ++ ++ ++ Reset user defined path setup. ++ ++ ++ ++ ++ qmt_map2jnx ++ ++ ++ ++ ++ <b>Note:</b> Usually QMapTool should detect all external tools by itself. If it does not, it's a bad setup and you should fix the PATH variable of your system. You can setup the paths manually, too, if you know what you are doing. But please keep in mind that GDAL needs a proper environment setup to function properly. If it's not setup properly you might get results but these can be off grid. ++ ++ ++ ++ ++ ITimeZoneSetup ++ ++ ++ Setup Time Zone ... ++ ++ ++ ++ ++ UTC ++ ++ ++ ++ ++ Local ++ ++ ++ ++ ++ Automatic ++ ++ ++ ++ ++ Print date/time in ++ ++ ++ ++ ++ long format, or ++ ++ ++ ++ ++ short format ++ ++ ++ ++ ++ IToolAddOverview ++ ++ ++ Form ++ ++ ++ ++ ++ do not translate ++ ++ ++ ++ ++ :2 ++ ++ ++ ++ ++ :4 ++ ++ ++ ++ ++ :8 ++ ++ ++ ++ ++ :16 ++ ++ ++ ++ ++ :32 ++ ++ ++ ++ ++ :64 ++ ++ ++ ++ ++ Remove all overview levels from map file. ++ ++ ++ ++ ++ Remove ++ ++ ++ ++ ++ Do not copy the overviews into the file itself. Add them as external file. ++ ++ ++ ++ ++ Overview as external file ++ ++ ++ ++ ++ Start ++ ++ ++ ++ ++ Cancel ++ ++ ++ ++ ++ For all files ++ ++ ++ ++ ++ <b style='color: red;'>No "gdaladdo" found. Please check setup!</b> ++ ++ ++ ++ ++ IToolCutMap ++ ++ ++ Form ++ ++ ++ ++ ++ do not translate ++ ++ ++ ++ ++ Output filename suffix ++ ++ ++ ++ ++ _cut ++ ++ ++ ++ ++ Create overviews for result. ++ ++ ++ ++ ++ Start ++ ++ ++ ++ ++ Cancel ++ ++ ++ ++ ++ For all files ++ ++ ++ ++ ++ <b style='color: red;'>No "gdalwarp" found. Please check setup!</b> ++ ++ ++ ++ ++ <b style='color: red;'>No "gdaladdo" found. Please check setup!</b> ++ ++ ++ ++ ++ IToolExport ++ ++ ++ Form ++ ++ ++ ++ ++ ++ do not translate ++ ++ ++ ++ ++ Garmin BirdsEye (*.jnx) ++ ++ ++ ++ ++ TwoNav Raster (*.rmap) ++ ++ ++ ++ ++ not implemented yet ++ ++ ++ ++ ++ Target File ++ ++ ++ ++ ++ Start ++ ++ ++ ++ ++ Cancel ++ ++ ++ ++ ++ <b style='color: red;'>No "qmt_map2jnx" found. Please check setup!</b> ++ ++ ++ ++ ++ Target Filename ++ ++ ++ ++ ++ IToolExportJnx ++ ++ ++ Form ++ ++ ++ ++ ++ ++ BirdsEye ++ ++ ++ ++ ++ Product ID ++ ++ ++ ++ ++ Copyright notice ++ ++ ++ ++ ++ ++ None ++ ++ ++ ++ ++ Product name ++ ++ ++ ++ ++ Description ++ ++ ++ ++ ++ JPEG ++ ++ ++ ++ ++ Quality ++ ++ ++ ++ ++ Chroma subsampling ++ ++ ++ ++ ++ 411 ++ ++ ++ ++ ++ 422 ++ ++ ++ ++ ++ 444 ++ ++ ++ ++ ++ Device ++ ++ ++ ++ ++ Z-Order ++ ++ ++ ++ ++ IToolGrid ++ ++ ++ Form ++ ++ ++ ++ ++ Grid Tool ++ ++ ++ ++ ++ do not translate ++ ++ ++ ++ ++ Ok ++ ++ ++ ++ ++ Cancel ++ ++ ++ ++ ++ Reset ++ ++ ++ ++ ++ IToolOverviewGroupBox ++ ++ ++ GroupBox ++ ++ ++ ++ ++ :2 ++ ++ ++ ++ ++ :4 ++ ++ ++ ++ ++ :8 ++ ++ ++ ++ ++ :16 ++ ++ ++ ++ ++ :32 ++ ++ ++ ++ ++ :64 ++ ++ ++ ++ ++ Do not copy the overviews into the file itself. Add them as external file. ++ ++ ++ ++ ++ Overview as external file ++ ++ ++ ++ ++ IToolPalettize ++ ++ ++ Form ++ ++ ++ ++ ++ ++ do not translate ++ ++ ++ ++ ++ Single files, filename suffix ++ ++ ++ ++ ++ _8bit ++ ++ ++ ++ ++ Combined file, filename: ++ ++ ++ ++ ++ Embed result into *.vrt file. ++ ++ ++ ++ ++ Create overviews for result. ++ ++ ++ ++ ++ Start ++ ++ ++ ++ ++ Cancel ++ ++ ++ ++ ++ <b style='color: red;'>No "gdaladdo" found. Please check setup!</b> ++ ++ ++ ++ ++ <b style='color: red;'>No "gdal_translate" found. Please check setup!</b> ++ ++ ++ ++ ++ <b style='color: red;'>No "qmt_rgb2pct" found. Please check setup!</b> ++ ++ ++ ++ ++ Select filename ++ ++ ++ ++ ++ IToolRefMap ++ ++ ++ Form ++ ++ ++ ++ ++ do not translate ++ ++ ++ ++ ++ Output filename suffix ++ ++ ++ ++ ++ _ref ++ ++ ++ ++ ++ Embed result into *.vrt file. ++ ++ ++ ++ ++ Create overviews for result. ++ ++ ++ ++ ++ Start ++ ++ ++ ++ ++ Cancel ++ ++ ++ ++ ++ For all files ++ ++ ++ ++ ++ <b style='color: red;'>No "gdalwarp" found. Please check setup!</b> ++ ++ ++ ++ ++ <b style='color: red;'>No "gdal_translate" found. Please check setup!</b> ++ ++ ++ ++ ++ <b style='color: red;'>No "gdaladdo" found. Please check setup!</b> ++ ++ ++ ++ ++ IUnit ++ ++ ++ ++ Error ++ ++ ++ ++ ++ Bad position format. Must be: "[N|S] ddd mm.sss [W|E] ddd mm.sss" or "[N|S] ddd.ddd [W|E] ddd.ddd" ++ ++ ++ ++ ++ Position values out of bounds. ++ ++ ++ ++ ++ IUnitsSetup ++ ++ ++ Setup units... ++ ++ ++ ++ ++ Nautical ++ ++ ++ ++ ++ Imperial ++ ++ ++ ++ ++ Metric ++ ++ ++ ++ ++ <b>Note:</b> For some GUI elements changing the units will not take effect until you restart QMapTool. ++ ++ ++ ++ +diff --git a/src/qmaptool/locale/qmaptool_de.ts b/src/qmaptool/locale/qmaptool_de.ts +new file mode 100644 +index 00000000..b3a43ef9 +--- /dev/null ++++ b/src/qmaptool/locale/qmaptool_de.ts +@@ -0,0 +1,1712 @@ ++ ++ ++ ++ ++ CCanvas ++ ++ ++ No map view available. ++ Keine Kartenansicht verfügbar. ++ ++ ++ ++ CCommandProcessor ++ ++ ++ Print debug output to console. ++ Debuginformation in der Konsole ausgeben. ++ ++ ++ ++ Print debug output to logfile (temp. path). ++ Debuginformation in eine Datei schreiben (temp. Pfad). ++ ++ ++ ++ Do not show splash screen. ++ Das Anfangsbild nicht zeigen. ++ ++ ++ ++ File with QMapTool configuration. ++ Eine Datei mit einer QMapTool-Konfiguration. ++ ++ ++ ++ file ++ Datei ++ ++ ++ ++ CDialogRefPoint ++ ++ ++ bad coordinate ++ ungültige Koordinate ++ ++ ++ ++ ++ Error ++ Fehler ++ ++ ++ ++ Bad value for X pixel. ++ Ungültiger Wert fur den X Wert des Bildpunktes. ++ ++ ++ ++ Bad value for Y pixel. ++ Ungültiger Wert fur den Y Wert des Bildpunktes. ++ ++ ++ ++ CDrawContextPixel ++ ++ Error... ++ Fehler... ++ ++ ++ Failed to load file: %1 ++ Datei laden fehlgeschlagen: %1 ++ ++ ++ File must be 8 bit palette or gray indexed. ++ Die Datei muss eine 8 Bit Farbpalette haben oder einen Graustufenindex. ++ ++ ++ (color table) ++ (Farbtabelle) ++ ++ ++ (unknown) ++ (unbekannt) ++ ++ ++ ++ Failed to load ++ Datei laden fehlgeschlagen ++ ++ ++ ++ CGdalFile ++ ++ ++ ++ ++ Error... ++ Fehler... ++ ++ ++ ++ ++ Failed to load file: %1 ++ Datei laden fehlgeschlagen: %1 ++ ++ ++ ++ File must be 8 bit palette or gray indexed. ++ Die Datei muss eine 8 Bit Farbpalette haben oder einen Graustufenindex. ++ ++ ++ ++ (color table) ++ (Farbtabelle) ++ ++ ++ ++ (RGB) ++ ++ ++ ++ ++ (RGBA) ++ ++ ++ ++ ++ (unknown) ++ (unbekannt) ++ ++ ++ ++ CGridPlacer ++ ++ ++ Select one of the corners and place the marker at the corresponding grid crossing on the map. All 4 corners have to be placed. ++ Wählen Sie eine Ecke aus und platzieren Sie die Markierung auf dem jeweiligen Gitterpunkt der Karte. Alle 4 Ecken müssen gesetzt werden. ++ ++ ++ ++ Point 1 - not set ++ Punkt 1 - nicht gesetzt ++ ++ ++ ++ Point 1 - ok ++ Punkt 1 - ok ++ ++ ++ ++ ++ Point 1 - bad ++ Punkt 1 - falsch ++ ++ ++ ++ Point 2 - ok ++ Punkt 2 - ok ++ ++ ++ ++ ++ Point 2 - bad ++ Punkt 2 - falsch ++ ++ ++ ++ Point 3 - ok ++ Punkt 3 - ok ++ ++ ++ ++ ++ Point 3 - bad ++ Punkt 3 - falsch ++ ++ ++ ++ Point 4 - ok ++ Punkt 4 - ok ++ ++ ++ ++ ++ Point 4 - bad ++ Punkt 4 - falsch ++ ++ ++ ++ Point 2 - not set ++ Punkt 2 - nicht gesetzt ++ ++ ++ ++ Point 3 - not set ++ Punkt 3 - nicht gesetzt ++ ++ ++ ++ Point 4 - not set ++ Punkt 4 - nicht gesetzt ++ ++ ++ ++ CGridSelArea ++ ++ ++ Select the area to be covered by the calculated reference points. Simply grab the corners of the selection rectangle with a left click and place them where you want with a second click. ++ Wählen Sie das Gebiet aus, für das Referenzpunkte berechnet werden sollen. Klicken Sie dazu einfach auf die Ecken des Auswahlrechtecks mit der linken Maustaste und platzieren die Ecke wo Sie wollen mit einem zweiten Klick. ++ ++ ++ ++ CGridSetRef ++ ++ ++ Valid coordinate formats: If the projection is lat/lon all values have to be in degree, e.g. "48.2" or "12.4". For all other projections values are either in multiple of meter or feet. If you are doing it wrong the entry field will turn red. ++ Gültige Koordinatenformate: Wenn die Projektion lat/lon Werte benötigt, müssen alle Eingaben in Grad sein, z.B. "48.2" oder "12.4". Für alle anderen Projektionen sind die Eingaben entweder in Meter oder in Fuß. Wenn etwas falsch ist, werden die Eingabefelder rot. ++ ++ ++ ++ CItemListWidget ++ ++ ++ Select files... ++ Dateien auswählen... ++ ++ ++ ++ COverlayCutMap ++ ++ ++ Delete mask... ++ Maske löschen... ++ ++ ++ ++ Are you sure to delete complete mask? ++ Wollen Sie wirklich die gesamte Maske löschen? ++ ++ ++ ++ Save mask... ++ Maske speichern... ++ ++ ++ ++ Load mask... ++ Maske laden... ++ ++ ++ ++ Failed... ++ Fehlgeschlagen... ++ ++ ++ ++ Not a shape file. ++ Keine Shape-Datei. ++ ++ ++ ++ COverlayGridTool ++ ++ ++ Before you proceed with 'ok': ++Please cross check all data once again. A bad reference coordinate will ruin all the work. Also cross check if the selected area contains as many reference points as possible at the border. You can easily delete points outside the map in the Reference Tool. But it's much more effort to set additional points in case you miss some. When you are done press 'ok' to transfer the derived reference points to the Reference Tool. ++ ++The next step will be to use the Reference Tool to adjust the position of all reference points to the real grid position on the map. ++ Bevor Sie mit 'ok' fortfahren: ++Bitte überprüfen Sie alle Eingaben erneut. Ein falsche Referenzkoordinate ruiniert die ganze Arbeit. Überprüfen Sie bitte auch, ob das ausgewählte Gebiet an den Grenzen so viele Referenzpunkte wie möglich beinhaltet. Punkte außerhalb der Karte lassen sich recht einfach löschen. Neue Punkte hinzufügen, sollten welche fehlen, ist wesentlich aufwändiger. Wenn Sie fertig sind drücken Sie 'ok', um die berechneten Punkte in das Referenzwerkzeug zu übertragen. ++ ++Im nächsten Schritte benutzen Sie das Referenzwerkzeug, um die Positionen von allen Referenzpunkten auf die tatsächlichen Gitterpunkte der Karte zu verschieben. ++ ++ ++ ++ COverlayRefMap ++ ++ ++ If you used the Grid Tool you have to fine tune the reference points by placing them as much as possible on the grid crossing. Be aware that if you over scale you get jumping points by rounding effects. Be precise but do not make religion out of the task. ++If your mouse focus is on the map you can use the N and B keys to jump forward an backward in the reference point list. ++The is also the option to fine tune the reference points in auto-mode. In this mode the next reference point is selected automatically right after you placed the current one. This is very convenient for a large number of reference points. ++ Wenn Sie das Gitterwerkzeug benutzt haben, müssen Sie die Punkte noch justieren, indem Sie sie auf die Gitterpunkte verschieben. Seien Sie sich bewusst, dass wenn Sie besonders nahe heranzoomen, die Punkte auf Grund von Rundungseffekten springen können. Seien sie beim Positionieren exakt, aber machen Sie daraus keine Religion. ++ ++Wenn ihr Mausfokus auf der Karte ist, können Sie die N und B Tasten benützen, um sich in der Referenzpunktliste vor und zurück zu bewegen. ++Es gibt außerdem die Option, die Referenzpunkte im Automode zu justieren. In diesem Modus wird der nächste Referenzpunkt automatisch ausgewählt, nachdem Sie den aktuellen Punkt platziert haben. Diese Funktion ist sehr praktisch, wenn Sie eine große Anzahl an Punkten bearbeiten wollen. ++ ++ ++ ++ Save reference points... ++ Referenzpunkte speichern... ++ ++ ++ ++ Load reference points... ++ Referenzpunkte laden... ++ ++ ++ ++ Delete all reference points... ++ Alle Referenzpunkte löschen... ++ ++ ++ ++ Are you sure to delete all reference points in the list? ++ Sind Sie sicher, dass Sie alle Referenzpunkte aus der Liste löschen wollen? ++ ++ ++ ++ Delete... ++ Löschen... ++ ++ ++ ++ Delete all selected reference points? ++ Alle ausgewählten Referenzpunkte löschen? ++ ++ ++ ++ COverlayRefMapPoint ++ ++ ++ bad coordinate ++ ungültige Koordinate ++ ++ ++ ++ CProjWizard ++ ++ ++ north ++ Nord ++ ++ ++ ++ south ++ Süd ++ ++ ++ ++ Error... ++ Fehler... ++ ++ ++ ++ The value ++'%1' ++is not a valid coordinate system definition: ++%2 ++ Die Eingabe ++'%1' ++ist keine gültige Koordinatensystemdefinition: ++%2 ++ ++ ++ ++ CSetupExtTools ++ ++ ++ ++ ++ ++ ++ ++ <b style='color: red;'>not found</b> ++ <b style='color: red;'>nicht gefunden</b> ++ ++ ++ ++ Select %1 binary... ++ Programm %1 auswählen... ++ ++ ++ ++ CShell ++ ++ ++ Execution of external program `%1` failed: ++ Ausführen der externen Anwendung '%1' fehlgeschlagen: ++ ++ ++ ++ Process cannot be started. ++ ++ Der Prozess kann nicht gestartet werden. ++ ++ ++ ++ Make sure the required packages are installed, `%1` exists and is executable. ++ ++ Stellen Sie sicher, dass alle benötigten Pakete installiert sind, '%1' vorhanden und ausführbar ist. ++ ++ ++ ++ External process crashed. ++ ++ Der externe Prozess ist abgestürzt. ++ ++ ++ ++ An unknown error occurred. ++ ++ Ein unbekannter Fehler ist aufgetreten. ++ ++ ++ ++ !!! failed !!! ++ ++ !!! fehlgeschlagen !!! ++ ++ ++ ++ ++Canceled by user's request. ++ ++ ++Durch den Benutzer abgebrochen. ++ ++ ++ ++ !!! done !!! ++ ++ !!! fertig !!! ++ ++ ++ ++ CToolAddOverview ++ ++ ++ Add Overviews ++ Übersichten hinzufügen ++ ++ ++ ++ Raster map files consume quite some memory if a larger area is displayed. Pre-calculated overview levels help to speed up loading and displaying the map. These overviews can be stored within the map file as well as an external file. GDAL can remove internally stored overviews, however it will not free the used space in the file. Therefore it's size will remain large. If you do not like that use the external option. ++ Rasterkarten benötigen recht viel Speicher, wenn ein größeres Gebiet angezeigt werden soll. Vorberechnete Übersichtsebenen helfen dabei, die Karte schnell zu laden und anzuzeigen. Diese Übersichtsebenen können in der Kartendatei oder als externe Datei gespeichert werden. GDAL kann zwar interne Übersichtsebenen entfernen, gibt dabei aber leider den Speicher nicht frei. Deswegen wird die Datei groß bleiben. Wenn Sie das nicht wünschen, dann sollten Sie die Option zur Erstellung einer externen Datei verwenden. ++ ++ ++ ++ CToolCutMap ++ ++ ++ Cut Map ++ Karte freistellen ++ ++ ++ ++ Paper maps usually have a border you don't want to have. To combine maps seamlessly you have to cut that border, replacing it by transparent pixel. This tool allows you to define a cut line and it will add an alpha channel for transparency to your map. ++ Papierkarten haben üblicherweise einen Rand, den man nicht dabei haben will. Um Karten blattschnittfrei zu kombinieren, muss man diesen Rand ausschneiden und durch transparente Bildpunkte ersetzen. Dieses Werkzeug ermöglicht es Ihnen, eine Schnittmaske zu erstellen, um damit einen Alphakanal mit den transparenten Bildpunkten zu erstellen. ++ ++ ++ ++ CToolExport ++ ++ ++ Export Maps ++ Karten exportieren ++ ++ ++ ++ To use the maps on your device you have to export them to the proprietary format supported by the device. Depending on the device this can vary from a single layer map to a map stack with maps of different scale. ++ Wenn Sie die Karten auf ihrem Gerät benützen wollen, müssen Sie diese in das jeweilige geschlossene Format. welches vom Gerät verwendet wird, exportieren. Abhängig vom Gerät kann das eine Karte mit einer einzelnen Auflösungsbene sein, oder eine mit mehreren Ebenen. ++ ++ ++ ++ Note: This tool will use all files in the list as a input. This will only work if all files have the same projection. ++ Hinweis: Dieses Werkzeug verwendet alle Dateien in der Liste als Eingabe. Das funktioniert nur, wenn alle Karten die selbe Projektion verwenden. ++ ++ ++ ++ Select filename... ++ Dateinamen auswählen... ++ ++ ++ ++ CToolGrid ++ ++ ++ By placing 4 reference points at the corners of a grid square and referencing them by their top left corner, the width and height, all the other grid points can be estimated. ++ Indem Sie 4 Referenzpunkte in den Ecken eines Gitterquadrates setzen und diese über die obere linke Ecke und die Breite und Höhe referenzieren, können alle anderen Gitterpunkte ungefähr berechnet werden. ++ ++ ++ ++ CToolPalettize ++ ++ ++ Add Color Palette ++ Farbtabelle erzeugen ++ ++ ++ ++ Usually you use RGBA color while referencing a map because the large color space allows you to scale and rotate the map without any loss of quality. But it results into rather large files. The file size can be optimized by using a color palette instead of the RGBA color space. The impact on quality is low as long as you do not want to scale or rotate the map. If you want to combine files with a color palette all files need to have the same palette. ++ Üblicherweise benützt man RGBA Farben während man eine Karte referenziert, weil der große Farbraum einem erlaubt, die Karte ohne Qualitätseinbuße zu drehen und zu skalieren. Leider wird deswegen auch die Datei sehr groß. Die Größe kann optimiert werden, wenn man eine Farbpalette anstelle von RGBA verwendet. Die Qualitätseinbußen sind gering, solange man die Karte nicht drehen oder skalieren möchte. Wenn Sie mehrer Karten zusammenfügen wolle, müssen alle dieselbe Palette benützen. ++ ++ ++ ++ Note: This tool will use all files in the list as a combined input to derive an optimal palette. This will only work if all files have the same projection and scale. ++ Anmerkung: Dieses Werkzeug benützt alle Dateien in der Liste als gemeinsame Eingabe, um eine optimale Palette zu berechnen. Das kann nur funktionieren, wenn alle Dateien die gleiche Projektion und Skalierung haben. ++ ++ ++ ++ Select filename... ++ Dateinamen auswählen... ++ ++ ++ ++ CToolRefMap ++ ++ ++ Reference Map ++ Karte referenzieren ++ ++ ++ ++ A scan of a paper map can be converted to a referenced raster map if you place at least three reference points on the map. The more points the better the result. If your map has a grid you can place points on that grid with the grid tool. ++ Eine gescannte Papierkarte kann in eine referenzierte Rasterkarte umgewandelt werden, indem Sie mindestens 3 Referenzpunkte auf der Karte angeben. Je mehr Punkte Sie setzen, desto besser. Wenn ihre Karte eine Gitter besitzt, können Sie Punkte auf dem Gitter mit dem Gitterwerkzeug setzen. ++ ++ ++ ++ IAbout ++ ++ ++ About... ++ Über... ++ ++ ++ ++ <b>QMapTool</b>, Version ++ <b>QMapTool</b>, Version ++ ++ ++ ++ ++ ++ ++ TextLabel ++ ++ ++ ++ ++ Qt ++ ++ ++ ++ ++ GDAL ++ ++ ++ ++ ++ Proj4 ++ ++ ++ ++ ++ This software is licensed under GPL3 or any later version ++ Diese Software steht unter der GPL3 Lizenz, oder einer neueren Version ++ ++ ++ ++ © 2017 Oliver Eichler (oliver.eichler@gmx.de) ++ ++ ++ ++ ++ ICoordFormatSetup ++ ++ ++ Coordinate Format... ++ Koordinatenformat... ++ ++ ++ ++ N48° 53' 39.6" E13° 31' 6.78" ++ ++ ++ ++ ++ N48.8943° E013.51855° ++ ++ ++ ++ ++ N48° 53.660 E013° 31.113 ++ ++ ++ ++ ++ <b>Note:</b> For some GUI elements changing the units will not take effect until you restart QMapTool. ++ <b>Anmerkung:</b> Bei einigen GUI Elementen wird die Änderung erst mit einem Neustart von QMapTool übernommen. ++ ++ ++ ++ IDialogRefPoint ++ ++ ++ Dialog ++ ++ ++ ++ ++ Coord. Map File [pixel] ++ Koord. Karte [pixel] ++ ++ ++ ++ x ++ ++ ++ ++ ++ y ++ ++ ++ ++ ++ Coord. lat/lon WGS84 [°] ++ Koord. lat/lon WGS84 [°] ++ ++ ++ ++ Bad position format. Must be: ++"[N|S] ddd mm.sss [W|E] ddd mm.sss" ++or ++"[N|S] ddd.ddd [W|E] ddd.ddd" ++ Falsches Format. Entweder: ++"[N|S] ddd mm.sss [W|E] ddd mm.sss" ++oder ++"[N|S] ddd.ddd [W|E] ddd.ddd" ++ ++ ++ ++ IGridPlacer ++ ++ ++ Form ++ ++ ++ ++ ++ Reset ++ Zurücksetzen ++ ++ ++ ++ Set Area ++ Abdeckung ++ ++ ++ ++ IGridSelArea ++ ++ ++ Form ++ ++ ++ ++ ++ TextLabel ++ ++ ++ ++ ++ IGridSetRef ++ ++ ++ Form ++ ++ ++ ++ ++ Grid Projection: ++ Gitterprojektion: ++ ++ ++ ++ ... ++ ++ ++ ++ ++ TextLabel ++ ++ ++ ++ ++ Easting ++ Ostwert ++ ++ ++ ++ Horiz. Spacing ++ horiz. Abstand ++ ++ ++ ++ Northing ++ Nordwert ++ ++ ++ ++ Vert. Spacing ++ vert. Abstand ++ ++ ++ ++ IItemListWidget ++ ++ ++ Form ++ ++ ++ ++ ++ Add map files to list ++ Kartendateien zur Liste hinzufügen ++ ++ ++ ++ ++ ++ ++ ... ++ ++ ++ ++ ++ Remove selected file from the list. ++ Ausgewählte Dateien aus der Liste entfernen. ++ ++ ++ ++ Clear complete list of map files. ++ Die komplette Kartendateiliste löschen. ++ ++ ++ ++ Reload the currently selected map. ++ Die aktuell ausgewählte Karte erneut laden. ++ ++ ++ ++ IMainWindow ++ ++ ++ MainWindow ++ ++ ++ ++ ++ Setup ++ Einrichten ++ ++ ++ ++ View ++ Ansicht ++ ++ ++ ++ Window ++ Fenster ++ ++ ++ ++ ? ++ ++ ++ ++ ++ Tools ++ Werkzeuge ++ ++ ++ ++ Shell ++ Shell ++ ++ ++ ++ About ++ Über ++ ++ ++ ++ Ext. Tools ++ Ext. Werkzeuge ++ ++ ++ ++ Setup paths to external tools, like gdalwarp etc. ++ Pfade zu den externen Werkzeugen, wie z.B. gdalwarp, einrichten. ++ ++ ++ ++ ++ Flip Mouse Wheel ++ Mausrad umdrehen ++ ++ ++ ++ ++ Setup Units ++ Einheiten einrichten ++ ++ ++ ++ Setup Coord. Format ++ Koordinatenformat einrichten ++ ++ ++ ++ Change the format coordinates are displayed ++ Das Format, in dem die Koordinaten angezeigt werden, ändern ++ ++ ++ ++ Show Tool Help ++ Hilfstexte anzeigen ++ ++ ++ ++ IOverlayCutMap ++ ++ ++ Form ++ ++ ++ ++ ++ Just move the map and zoom. ++ Die Karte verschieben und zoomen. ++ ++ ++ ++ Add point to mask. ++ Punkte zur Maske hinzufügen. ++ ++ ++ ++ ++ ++ ++ ++ ++ ... ++ ++ ++ ++ ++ Move point of mask. ++ Maskenpunkte verschieben. ++ ++ ++ ++ Remove point from mask. ++ Punkte aus der Maske entfernen. ++ ++ ++ ++ Remove complete cut mask. ++ Die komplette Freistellmaske entfernen. ++ ++ ++ ++ Load cut mask from shape file. ++ Freistellmaske aus einer Shapedatei laden. ++ ++ ++ ++ Save cut mask to shape file. ++ Freistellmaske in einer Shapedatei speichern. ++ ++ ++ ++ IOverlayGridTool ++ ++ ++ Form ++ ++ ++ ++ ++ do not translate ++ ++ ++ ++ ++ IOverlayRefMap ++ ++ ++ Form ++ ++ ++ ++ ++ Just move the map and zoom. ++ Die Karte verschieben und zoomen. ++ ++ ++ ++ Add reference point. ++ Referenzpunkte hinzufügen. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ... ++ ++ ++ ++ ++ Move reference point. ++ Referenzpunkte verschieben. ++ ++ ++ ++ Remove single reference point. ++ Referenzpunkte löschen. ++ ++ ++ ++ Move reference points with auto mode. This will pickup the next point after you moved a reference point. ++ Referenzpunkte im Automode verschieben. Nachdem der aktuelle Punkt verschoben wurde, wird automatisch der Nächste genommen. ++ ++ ++ ++ Remove all reference points. ++ Alle Referenzpunkte löschen. ++ ++ ++ ++ Switch to the Grid Tool. ++ Auf das Gitterwerkzeug umschalten. ++ ++ ++ ++ Load reference points from GCP file. ++ Referenzpunkte aus einer GCP Datei lesen. ++ ++ ++ ++ Save reference points into GCP file. ++ Referenzpunkte in eine GCP Datei speichern. ++ ++ ++ ++ Sort list of reference points. ++ Die Liste der Referenzpunkte sortieren. ++ ++ ++ ++ (x, y)[pixel] ++ ++ ++ ++ ++ (lat, lon)[°] ++ ++ ++ ++ ++ TextLabel ++ ++ ++ ++ ++ Final Map Projection: ++ Endgültige Kartenprojektion: ++ ++ ++ ++ Enter a valid projection string. Valid strings are "+proj..." or "+init=epsg:...". ++ Geben Sie einen gültigen Projektionstext ein. Gültige Formen sind "+proj=..." oder "+init=...". ++ ++ ++ ++ Start projection wizard. ++ Den Projektionsassistenten öffnen. ++ ++ ++ ++ Delete ++ Löschen ++ ++ ++ ++ IProjWizard ++ ++ ++ Proj4 Wizard ++ Proj4 Assistent ++ ++ ++ ++ Mercator ++ ++ ++ ++ ++ UTM ++ ++ ++ ++ ++ zone ++ Zone ++ ++ ++ ++ user defined ++ benutzerdefiniert ++ ++ ++ ++ Datum ++ Datum ++ ++ ++ ++ World Mercator (OSM) ++ ++ ++ ++ ++ Result: ++ Ergebnis: ++ ++ ++ ++ UPS North (North Pole) ++ ++ ++ ++ ++ UPS South (South Pole) ++ ++ ++ ++ ++ Projection ++ Projektion ++ ++ ++ ++ ISetupExtTools ++ ++ ++ Setup Ext. Tools ++ Externe Werkzeuge einstellen ++ ++ ++ ++ ++ ++ ++ ++ ++ <b style='color: red;'>not found</b> ++ <b style='color: red;'>nicht gefunden</b> ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ... ++ ++ ++ ++ ++ gdal_translate: ++ ++ ++ ++ ++ gdalbuildvrt ++ ++ ++ ++ ++ gdaladdo: ++ ++ ++ ++ ++ gdalwarp: ++ ++ ++ ++ ++ ++ ++ ++ ++ Setup user defined path. ++ Benutzerdefinierten Pfad einstellen. ++ ++ ++ ++ qmt_rgb2pct ++ ++ ++ ++ ++ ++ ++ ++ ++ Reset user defined path setup. ++ Benutzerdefinierten Pfad zurücksetzen. ++ ++ ++ ++ qmt_map2jnx ++ ++ ++ ++ ++ <b>Note:</b> Usually QMapTool should detect all external tools by itself. If it does not, it's a bad setup and you should fix the PATH variable of your system. You can setup the paths manually, too, if you know what you are doing. But please keep in mind that GDAL needs a proper environment setup to function properly. If it's not setup properly you might get results but these can be off grid. ++ <b>Anmerkung:</b> Normalerweise sollte QMapTool alle externen Werkzeuge selber finden. Wenn das nicht gelingt, liegt es in der Regel an einer schlechten Einstellung und Sie sollten die PATH Variable ihres Systems überprüfen. Man kann die Werkzeugpfade auch selber setzen. Vorausgesetzt, man weiß was man macht. Bitte bedenken Sie, dass GDAL eine ordentlich aufgesetzte Umgebung benötigt, um fachgerecht zu funktionieren. Wenn dem nicht so ist, können durchaus Ergebnisse erzielt werden, diese können aber verschoben sein. ++ ++ ++ ++ ITimeZoneSetup ++ ++ ++ Setup Time Zone ... ++ Zeitzone einstellen... ++ ++ ++ ++ UTC ++ ++ ++ ++ ++ Local ++ Lokal ++ ++ ++ ++ Automatic ++ Automatisch ++ ++ ++ ++ Print date/time in ++ Datum/Zeit anzeigen im ++ ++ ++ ++ long format, or ++ langen Format ++ ++ ++ ++ short format ++ kurzen Format ++ ++ ++ ++ IToolAddOverview ++ ++ ++ Form ++ ++ ++ ++ ++ do not translate ++ ++ ++ ++ ++ :2 ++ ++ ++ ++ ++ :4 ++ ++ ++ ++ ++ :8 ++ ++ ++ ++ ++ :16 ++ ++ ++ ++ ++ :32 ++ ++ ++ ++ ++ :64 ++ ++ ++ ++ ++ Remove all overview levels from map file. ++ Alle Übersichten aus der Kartendatei entfernen. ++ ++ ++ ++ Remove ++ Löschen ++ ++ ++ ++ Do not copy the overviews into the file itself. Add them as external file. ++ Die Übersichten nicht in der Datei selbst anlegen. Als extra Datei hinzufügen. ++ ++ ++ ++ Overview as external file ++ Übersichten als externe Datei ++ ++ ++ ++ Start ++ Start ++ ++ ++ ++ Cancel ++ Abbrechen ++ ++ ++ ++ For all files ++ Für alle Dateien ++ ++ ++ ++ <b style='color: red;'>No "gdaladdo" found. Please check setup!</b> ++ <b style='color: red;'>"gdaladdo"nicht gefunden. Bitte überprüfen Sie die Einstellungen!</b> ++ ++ ++ ++ IToolCutMap ++ ++ ++ Form ++ ++ ++ ++ ++ do not translate ++ ++ ++ ++ ++ Output filename suffix ++ Suffix der Ausgabedatei ++ ++ ++ ++ _cut ++ ++ ++ ++ ++ Create overviews for result. ++ Übersichten für das Ergebnis erzeugen. ++ ++ ++ ++ Start ++ Start ++ ++ ++ ++ Cancel ++ Abbrechen ++ ++ ++ ++ For all files ++ Für alle Dateien ++ ++ ++ ++ <b style='color: red;'>No "gdalwarp" found. Please check setup!</b> ++ <b style='color: red;'>"gdalwarp"nicht gefunden. Bitte überprüfen Sie die Einstellungen!</b> ++ ++ ++ ++ <b style='color: red;'>No "gdaladdo" found. Please check setup!</b> ++ <b style='color: red;'>"gdaladdo"nicht gefunden. Bitte überprüfen Sie die Einstellungen!</b> ++ ++ ++ ++ IToolExport ++ ++ ++ Form ++ ++ ++ ++ ++ ++ do not translate ++ ++ ++ ++ ++ Garmin BirdsEye (*.jnx) ++ ++ ++ ++ ++ TwoNav Raster (*.rmap) ++ ++ ++ ++ ++ not implemented yet ++ noch nicht eingebaut ++ ++ ++ ++ Target File ++ Zieldatei ++ ++ ++ ++ Start ++ Start ++ ++ ++ ++ Cancel ++ Abbrechen ++ ++ ++ ++ <b style='color: red;'>No "qmt_map2jnx" found. Please check setup!</b> ++ <b style='color: red;'>"qmt_map2jnx"nicht gefunden. Bitte überprüfen Sie die Einstellungen!</b> ++ ++ ++ ++ Target Filename ++ Dateiname der Zieldatei ++ ++ ++ ++ IToolExportJnx ++ ++ ++ Form ++ ++ ++ ++ ++ ++ BirdsEye ++ ++ ++ ++ ++ Product ID ++ Produkt ID ++ ++ ++ ++ Copyright notice ++ Urheberhinweis ++ ++ ++ ++ ++ None ++ Nichts ++ ++ ++ ++ Product name ++ Produktname ++ ++ ++ ++ Description ++ Beschreibung ++ ++ ++ ++ JPEG ++ ++ ++ ++ ++ Quality ++ Qualität ++ ++ ++ ++ ++ Chroma subsampling ++ Halbttonunterabtastung ++ ++ ++ ++ 411 ++ ++ ++ ++ ++ 422 ++ ++ ++ ++ ++ 444 ++ ++ ++ ++ ++ Device ++ Gerät ++ ++ ++ ++ Z-Order ++ Reihenfolge (Z-Achse) ++ ++ ++ ++ IToolGrid ++ ++ ++ Form ++ ++ ++ ++ ++ Grid Tool ++ Gitterwerkzeug ++ ++ ++ ++ do not translate ++ ++ ++ ++ ++ Ok ++ OK ++ ++ ++ ++ Cancel ++ Abbrechen ++ ++ ++ ++ Reset ++ Zurücksetzen ++ ++ ++ ++ IToolOverviewGroupBox ++ ++ ++ GroupBox ++ ++ ++ ++ ++ :2 ++ ++ ++ ++ ++ :4 ++ ++ ++ ++ ++ :8 ++ ++ ++ ++ ++ :16 ++ ++ ++ ++ ++ :32 ++ ++ ++ ++ ++ :64 ++ ++ ++ ++ ++ Do not copy the overviews into the file itself. Add them as external file. ++ Die Übersichten nicht in der Datei selber anlegen. Als extra Datei hinzufügen. ++ ++ ++ ++ Overview as external file ++ Übersichten als externe Datei ++ ++ ++ ++ IToolPalettize ++ ++ ++ Form ++ ++ ++ ++ ++ ++ do not translate ++ ++ ++ ++ ++ Single files, filename suffix ++ Einzelne Dateien, Dateinamensuffix ++ ++ ++ ++ _8bit ++ ++ ++ ++ ++ Combined file, filename: ++ In einer Datei zusammenfassen, Dateiname: ++ ++ ++ ++ Embed result into *.vrt file. ++ Ergebnis in eine *.vrt Datei einbetten. ++ ++ ++ ++ Create overviews for result. ++ Übersichten für das Ergebnis erzeugen. ++ ++ ++ ++ Start ++ Start ++ ++ ++ ++ Cancel ++ Abbrechen ++ ++ ++ ++ <b style='color: red;'>No "gdaladdo" found. Please check setup!</b> ++ <b style='color: red;'>"gdaladdo"nicht gefunden. Bitte überprüfen Sie die Einstellungen!</b> ++ ++ ++ ++ <b style='color: red;'>No "gdal_translate" found. Please check setup!</b> ++ <b style='color: red;'>"gdal_translate"nicht gefunden. Bitte überprüfen Sie die Einstellungen!</b> ++ ++ ++ ++ <b style='color: red;'>No "qmt_rgb2pct" found. Please check setup!</b> ++ <b style='color: red;'>"qmt_rgb2pct"nicht gefunden. Bitte überprüfen Sie die Einstellungen!</b> ++ ++ ++ ++ Select filename ++ Dateinamen auswählen ++ ++ ++ ++ IToolRefMap ++ ++ ++ Form ++ ++ ++ ++ ++ do not translate ++ ++ ++ ++ ++ Output filename suffix ++ Suffix der Ausgabedatei ++ ++ ++ ++ _ref ++ ++ ++ ++ ++ Embed result into *.vrt file. ++ Ergebnis in eine *.vrt Datei einbetten. ++ ++ ++ ++ Create overviews for result. ++ Übersichten für das Ergebnis erzeugen. ++ ++ ++ ++ Start ++ Start ++ ++ ++ ++ Cancel ++ Abbrechen ++ ++ ++ ++ For all files ++ Für alle Dateien ++ ++ ++ ++ <b style='color: red;'>No "gdalwarp" found. Please check setup!</b> ++ <b style='color: red;'>"gdalwarp"nicht gefunden. Bitte überprüfen Sie die Einstellungen!</b> ++ ++ ++ ++ <b style='color: red;'>No "gdal_translate" found. Please check setup!</b> ++ <b style='color: red;'>"gdal_translate"nicht gefunden. Bitte überprüfen Sie die Einstellungen!</b> ++ ++ ++ ++ <b style='color: red;'>No "gdaladdo" found. Please check setup!</b> ++ <b style='color: red;'>"gdaladdo"nicht gefunden. Bitte überprüfen Sie die Einstellungen!</b> ++ ++ ++ ++ IUnit ++ ++ ++ ++ Error ++ Fehler ++ ++ ++ ++ Bad position format. Must be: "[N|S] ddd mm.sss [W|E] ddd mm.sss" or "[N|S] ddd.ddd [W|E] ddd.ddd" ++ Falsches Format. Entweder: ++"[N|S] ddd mm.sss [W|E] ddd mm.sss" ++oder ++"[N|S] ddd.ddd [W|E] ddd.ddd" ++ ++ ++ ++ Position values out of bounds. ++ Positionswerte außerhalb der Grenzen. ++ ++ ++ ++ IUnitsSetup ++ ++ ++ Setup units... ++ Einheiten einrichten... ++ ++ ++ ++ Nautical ++ nautisch ++ ++ ++ ++ Imperial ++ imperial ++ ++ ++ ++ Metric ++ metrisch ++ ++ ++ ++ <b>Note:</b> For some GUI elements changing the units will not take effect until you restart QMapTool. ++ <b>Anmerkung:</b> Bei einigen GUI Elementen wird die Änderung erst mit einem Neustart von QMapTool übernommen. ++ ++ ++ +diff --git a/src/qmaptool/locale/qmaptool_es.ts b/src/qmaptool/locale/qmaptool_es.ts +new file mode 100644 +index 00000000..4b6a5cb3 +--- /dev/null ++++ b/src/qmaptool/locale/qmaptool_es.ts +@@ -0,0 +1,1715 @@ ++ ++ ++ ++ ++ CCanvas ++ ++ ++ No map view available. ++ Vista de mapa no disponible. ++ ++ ++ ++ CCommandProcessor ++ ++ ++ Print debug output to console. ++ Mostrar salida de depuración en la consola. ++ ++ ++ ++ Print debug output to logfile (temp. path). ++ Mostrar salida de depuración en archivo log (Carpeta temporal). ++ ++ ++ ++ Do not show splash screen. ++ No mostrar pantalla de bienvenida. ++ ++ ++ ++ File with QMapTool configuration. ++ Archivo con la configuración de QMapTool. ++ ++ ++ ++ file ++ archivo ++ ++ ++ ++ CDialogRefPoint ++ ++ ++ bad coordinate ++ Coordenada incorrecta ++ ++ ++ ++ ++ Error ++ Error ++ ++ ++ ++ Bad value for X pixel. ++ Valor incorrecto para el pixel X. ++ ++ ++ ++ Bad value for Y pixel. ++ Valor incorrecto para el pixel Y. ++ ++ ++ ++ CDrawContextPixel ++ ++ Error... ++ Error... ++ ++ ++ Failed to load file: %1 ++ Fallo al cargar el archivo: %1 ++ ++ ++ File must be 8 bit palette or gray indexed. ++ El archivo debe de tener una paleta superior a 8 bits o gris indexado. ++ ++ ++ (color table) ++ (tabla de color) ++ ++ ++ (RGB) ++ (RGB) ++ ++ ++ (RGBA) ++ (RGBA) ++ ++ ++ (unknown) ++ (desconocido) ++ ++ ++ ++ Failed to load ++ Fallo al cargar ++ ++ ++ ++ CGdalFile ++ ++ ++ ++ ++ Error... ++ Error... ++ ++ ++ ++ ++ Failed to load file: %1 ++ Fallo al cargar el archivo: %1 ++ ++ ++ ++ File must be 8 bit palette or gray indexed. ++ El archivo debe de tener una paleta superior a 8 bits o gris indexado. ++ ++ ++ ++ (color table) ++ (tabla de color) ++ ++ ++ ++ (RGB) ++ (RGB) ++ ++ ++ ++ (RGBA) ++ (RGBA) ++ ++ ++ ++ (unknown) ++ (desconocido) ++ ++ ++ ++ CGridPlacer ++ ++ ++ Select one of the corners and place the marker at the corresponding grid crossing on the map. All 4 corners have to be placed. ++ Seleccionar una de las esquinas y colocar el marcador en el cruce de cuadrícula correspondiente en el mapa. Las 4 esquinas deben de estar colocadas. ++ ++ ++ ++ Point 1 - not set ++ Punto 1 - no establecido ++ ++ ++ ++ Point 1 - ok ++ Punto 1 - ok ++ ++ ++ ++ ++ Point 1 - bad ++ Punto 1 - error ++ ++ ++ ++ Point 2 - ok ++ Punto 2 - ok ++ ++ ++ ++ ++ Point 2 - bad ++ Punto 2 - error ++ ++ ++ ++ Point 3 - ok ++ Punto 3 - ok ++ ++ ++ ++ ++ Point 3 - bad ++ Punto 3 - error ++ ++ ++ ++ Point 4 - ok ++ Punto 4 - ok ++ ++ ++ ++ ++ Point 4 - bad ++ Punto 4 - error ++ ++ ++ ++ Point 2 - not set ++ Punto 2 - no establecido ++ ++ ++ ++ Point 3 - not set ++ Punto 3 - no establecido ++ ++ ++ ++ Point 4 - not set ++ Punto 4 - no establecido ++ ++ ++ ++ CGridSelArea ++ ++ ++ Select the area to be covered by the calculated reference points. Simply grab the corners of the selection rectangle with a left click and place them where you want with a second click. ++ Seleccionar el área cubierta por los puntos de referencia calculados. Coger las esquinas de la selección rectangular con un clic izquierdo y soltarlas en el nuevo emplazamiento con un segundo clic. ++ ++ ++ ++ CGridSetRef ++ ++ ++ Valid coordinate formats: If the projection is lat/lon all values have to be in degree, e.g. "48.2" or "12.4". For all other projections values are either in multiple of meter or feet. If you are doing it wrong the entry field will turn red. ++ Formatos de coordenadas válidos: si la proyección es lat / lon, todos los valores deben estar en grados, p. "48,2" o "12,4". Para el resto de las proyecciones, los valores están en múltiplos de metro o pies. Si te equivocas, el campo de entrada se pone rojo. ++ ++ ++ ++ CItemListWidget ++ ++ ++ Select files... ++ Seleccionar archivos... ++ ++ ++ ++ COverlayCutMap ++ ++ ++ Delete mask... ++ Borrar máscara... ++ ++ ++ ++ Are you sure to delete complete mask? ++ ¿Estás seguro de eliminar la máscara completa? ++ ++ ++ ++ Save mask... ++ Guardar máscara... ++ ++ ++ ++ Load mask... ++ Cargar máscara... ++ ++ ++ ++ Failed... ++ Fallo... ++ ++ ++ ++ Not a shape file. ++ No es un archivo shape. ++ ++ ++ ++ COverlayGridTool ++ ++ ++ Before you proceed with 'ok': ++Please cross check all data once again. A bad reference coordinate will ruin all the work. Also cross check if the selected area contains as many reference points as possible at the border. You can easily delete points outside the map in the Reference Tool. But it's much more effort to set additional points in case you miss some. When you are done press 'ok' to transfer the derived reference points to the Reference Tool. ++ ++The next step will be to use the Reference Tool to adjust the position of all reference points to the real grid position on the map. ++ Antes de continuar pulsando 'ok': ++Verificar los datos una vez más. Una coordenada errónea en la referencia arruinará todo el trabajo. Verificar también si el área seleccionada contiene tantos puntos como sea posible en el borde. Puedes eliminar puntos fácilmente fuera del mapa en la Herramienta de Referencia, pero es mas trabajoso establecer puntos adicionales en caso de que se pierda alguno. Cuando hayas terminado, pulsar 'ok' para transferir los puntos a la Herramienta de Referencia. ++ ++El siguiente paso será usar la herramienta de referencia para ajustar la posición de todos los puntos a la posición de la cuadrícula real del mapa. ++ ++ ++ ++ COverlayRefMap ++ ++ ++ If you used the Grid Tool you have to fine tune the reference points by placing them as much as possible on the grid crossing. Be aware that if you over scale you get jumping points by rounding effects. Be precise but do not make religion out of the task. ++If your mouse focus is on the map you can use the N and B keys to jump forward an backward in the reference point list. ++The is also the option to fine tune the reference points in auto-mode. In this mode the next reference point is selected automatically right after you placed the current one. This is very convenient for a large number of reference points. ++ Si se utilizó la Herramienta de Cuadrícula, hay que ajustar los puntos de referencia colocándolos en el cruce de la cuadrícula lo máximo posible. Ten en cuenta que si sobre escalas obtendrás puntos con valores redondeados, se necesita precisión, pero tampoco es necesario exagerar. ++Si el mapa esta en el primer plano del foco del ratón, puedes usar las teclas N y B para avanzar y retroceder en la lista de puntos de referencia. ++También es la opción para ajustar los puntos de referencia en modo automático. En este modo, el siguiente punto de referencia se selecciona automáticamente justo después de que coloques el actual, muy conveniente cuando los puntos son muchos. ++ ++ ++ ++ Save reference points... ++ Guardar puntos de referencia... ++ ++ ++ ++ Load reference points... ++ Cargar puntos de referencia... ++ ++ ++ ++ Delete all reference points... ++ Borrar todos los puntos de referencia... ++ ++ ++ ++ Are you sure to delete all reference points in the list? ++ ¿Estás seguro de borrar todos los puntos de la lista? ++ ++ ++ ++ Delete... ++ Borrar... ++ ++ ++ ++ Delete all selected reference points? ++ ¿Borrar los puntos seleccionados? ++ ++ ++ ++ COverlayRefMapPoint ++ ++ ++ bad coordinate ++ Coordenada errónea ++ ++ ++ ++ CProjWizard ++ ++ ++ north ++ Norte ++ ++ ++ ++ south ++ Sur ++ ++ ++ ++ Error... ++ Error... ++ ++ ++ ++ The value ++'%1' ++is not a valid coordinate system definition: ++%2 ++ El valor ++'%1' ++No es una definición válida del sistema de coordenadas: ++%2 ++ ++ ++ ++ CSetupExtTools ++ ++ ++ ++ ++ ++ ++ ++ <b style='color: red;'>not found</b> ++ <b style='color: red;'>no encontrado</b> ++ ++ ++ ++ Select %1 binary... ++ Seleccionar %1 binario ++ ++ ++ ++ CShell ++ ++ ++ Execution of external program `%1` failed: ++ La ejecución del programa externo `%1` falló: ++ ++ ++ ++ Process cannot be started. ++ ++ El proceso no se puede iniciar. ++ ++ ++ ++ ++ Make sure the required packages are installed, `%1` exists and is executable. ++ ++ Asegúrate de que los paquetes requeridos están instalados, `%1` existe y es ejecutable. ++ ++ ++ ++ External process crashed. ++ ++ Proceso externo bloqueado. ++ ++ ++ ++ An unknown error occurred. ++ ++ Ha ocurrido un error desconocido ++ ++ ++ ++ !!! failed !!! ++ ++ !!! falló !!! ++ ++ ++ ++ ++Canceled by user's request. ++ ++ Cancelado por el usuario. ++ ++ ++ ++ !!! done !!! ++ ++ ¡¡¡ hecho !!! ++ ++ ++ ++ CToolAddOverview ++ ++ ++ Add Overviews ++ Añadir niveles de zoom ++ ++ ++ ++ Raster map files consume quite some memory if a larger area is displayed. Pre-calculated overview levels help to speed up loading and displaying the map. These overviews can be stored within the map file as well as an external file. GDAL can remove internally stored overviews, however it will not free the used space in the file. Therefore it's size will remain large. If you do not like that use the external option. ++ Cuando el área es muy grande los archivos de los mapas raster son muy pesados. Los distintos niveles de zoom aceleran la carga y visualización. Se pueden almacenar en el mismo archivo que el mapa o en otro distinto. GDAL puede eliminar los niveles de zoom almacenados internamente pero el tamaño del archivo seguirá siendo el mismo, no así cuando se almacenan en archivo externo. ++ ++ ++ ++ CToolCutMap ++ ++ ++ Cut Map ++ Cortar Mapa ++ ++ ++ ++ Paper maps usually have a border you don't want to have. To combine maps seamlessly you have to cut that border, replacing it by transparent pixel. This tool allows you to define a cut line and it will add an alpha channel for transparency to your map. ++ Los mapas en papel suelen tener un marco en blanco innecesario. Para unir mapas a la perfección, es necesario eliminar ese borde y reemplazarlo por un píxel transparente. Esta herramienta te permite definir una línea de corte y agregar un canal alfa para la transparencia del mapa. ++ ++ ++ ++ CToolExport ++ ++ ++ Export Maps ++ Exportar Mapas ++ ++ ++ ++ To use the maps on your device you have to export them to the proprietary format supported by the device. Depending on the device this can vary from a single layer map to a map stack with maps of different scale. ++ Para poder ver los mapas en tu dispositivo hay que exportarlos a un formato que este admita, puede ser necesario un mapa multicapa con distintos niveles de zoom o de una sola capa. ++ ++ ++ ++ Note: This tool will use all files in the list as a input. This will only work if all files have the same projection. ++ Nota: Esta herramienta usa todos los archivos de la lista. Es necesario que todos tengan la misma proyección. ++ ++ ++ ++ Select filename... ++ Seleccionar nombre de archivo... ++ ++ ++ ++ CToolGrid ++ ++ ++ By placing 4 reference points at the corners of a grid square and referencing them by their top left corner, the width and height, all the other grid points can be estimated. ++ Al poner los 4 puntos de referencia en las esquinas de un cuadrado de la cuadrícula y referenciarlos en ancho y alto por su esquina superior izquierda, todos los otros puntos se pueden estimar. ++ ++ ++ ++ CToolPalettize ++ ++ ++ Add Color Palette ++ Añadir Paleta de Color ++ ++ ++ ++ Usually you use RGBA color while referencing a map because the large color space allows you to scale and rotate the map without any loss of quality. But it results into rather large files. The file size can be optimized by using a color palette instead of the RGBA color space. The impact on quality is low as long as you do not want to scale or rotate the map. If you want to combine files with a color palette all files need to have the same palette. ++ Por lo general, se utiliza color RGBA al referenciar un mapa, ya que el gran espacio de color permite escalar y rotar sin pérdida de calidad, pero los archivos resultan ser muy grandes, se puede optimizar utilizando una paleta de colores en lugar del espacio de color RGBA. El impacto en la calidad es bajo siempre y cuando no quieras escalar o rotar. Si quieres combinar archivos con paleta de colores, todos deben de tener la misma. ++ ++ ++ ++ Note: This tool will use all files in the list as a combined input to derive an optimal palette. This will only work if all files have the same projection and scale. ++ Nota: Esta herramienta utilizará los archivos de la lista para obtener una paleta óptima. Solo funcionará si todos los archivos tienen la misma proyección y escala. ++ ++ ++ ++ Select filename... ++ Seleccionar nombre de archivo... ++ ++ ++ ++ CToolRefMap ++ ++ ++ Reference Map ++ Referenciar Mapa ++ ++ ++ ++ A scan of a paper map can be converted to a referenced raster map if you place at least three reference points on the map. The more points the better the result. If your map has a grid you can place points on that grid with the grid tool. ++ Un mapa de papel escaneado se puede convertir en un mapa ráster referenciado poniendo al menos tres puntos de referencia en el mapa. Cuantos más puntos, mejor es el resultado. Si el mapa tiene una cuadrícula, se pueden poner puntos en esa cuadrícula con la herramienta de cuadrícula. ++ ++ ++ ++ IAbout ++ ++ ++ About... ++ Acerca de... ++ ++ ++ ++ <b>QMapTool</b>, Version ++ <b>QMapTool</b>, Versión ++ ++ ++ ++ ++ ++ ++ TextLabel ++ ++ ++ ++ ++ Qt ++ ++ ++ ++ ++ GDAL ++ ++ ++ ++ ++ Proj4 ++ ++ ++ ++ ++ This software is licensed under GPL3 or any later version ++ Este programa está bajo licencia GPL3 o posterior ++ ++ ++ ++ © 2017 Oliver Eichler (oliver.eichler@gmx.de) ++ ++ ++ ++ ++ ICoordFormatSetup ++ ++ ++ Coordinate Format... ++ Formato de Coordenadas... ++ ++ ++ ++ N48° 53' 39.6" E13° 31' 6.78" ++ ++ ++ ++ ++ N48.8943° E013.51855° ++ ++ ++ ++ ++ N48° 53.660 E013° 31.113 ++ ++ ++ ++ ++ <b>Note:</b> For some GUI elements changing the units will not take effect until you restart QMapTool. ++ <b>Nota:</b> El cambio de las unidades de algunos elementos no se producirá hasta el reinicio de QMapTool. ++ ++ ++ ++ IDialogRefPoint ++ ++ ++ Dialog ++ ++ ++ ++ ++ Coord. Map File [pixel] ++ Coord. archivo Map [pixel] ++ ++ ++ ++ x ++ ++ ++ ++ ++ y ++ ++ ++ ++ ++ Coord. lat/lon WGS84 [°] ++ ++ ++ ++ ++ Bad position format. Must be: ++"[N|S] ddd mm.sss [W|E] ddd mm.sss" ++or ++"[N|S] ddd.ddd [W|E] ddd.ddd" ++ Formato de posición incorrecto. Debe ser: ++"[N|S] ddd mm.sss [W|E] ddd mm.sss" ++o ++"[N|S] ddd.ddd [W|E] ddd.ddd" ++ ++ ++ ++ IGridPlacer ++ ++ ++ Form ++ ++ ++ ++ ++ Reset ++ Reiniciar ++ ++ ++ ++ Set Area ++ Establecer área ++ ++ ++ ++ IGridSelArea ++ ++ ++ Form ++ ++ ++ ++ ++ TextLabel ++ ++ ++ ++ ++ IGridSetRef ++ ++ ++ Form ++ ++ ++ ++ ++ Grid Projection: ++ Proyección de la Cuadrícula: ++ ++ ++ ++ ... ++ ++ ++ ++ ++ TextLabel ++ ++ ++ ++ ++ Easting ++ ++ ++ ++ ++ Horiz. Spacing ++ Espaciado horizontal ++ ++ ++ ++ Northing ++ ++ ++ ++ ++ Vert. Spacing ++ Espaciado vertical ++ ++ ++ ++ IItemListWidget ++ ++ ++ Form ++ ++ ++ ++ ++ Add map files to list ++ Añadir archivos de mapa a la lista ++ ++ ++ ++ ++ ++ ++ ... ++ ++ ++ ++ ++ Remove selected file from the list. ++ Borrar archivo seleccionado de la lista. ++ ++ ++ ++ Clear complete list of map files. ++ Borrar lista completa de archivos de mapa. ++ ++ ++ ++ Reload the currently selected map. ++ Recargar mapa seleccionado. ++ ++ ++ ++ IMainWindow ++ ++ ++ MainWindow ++ ++ ++ ++ ++ Setup ++ Configuración ++ ++ ++ ++ View ++ Ver ++ ++ ++ ++ Window ++ Ventana ++ ++ ++ ++ ? ++ ++ ++ ++ ++ Tools ++ Herramientas ++ ++ ++ ++ Shell ++ ++ ++ ++ ++ About ++ Acerca de ++ ++ ++ ++ Ext. Tools ++ Herramientas ext. ++ ++ ++ ++ Setup paths to external tools, like gdalwarp etc. ++ Configurar rutas de las herramientas ext. ++ ++ ++ ++ ++ Flip Mouse Wheel ++ Invertir rueda del ratón ++ ++ ++ ++ ++ Setup Units ++ Configurar unidades ++ ++ ++ ++ Setup Coord. Format ++ Configurar formato de coordenadas ++ ++ ++ ++ Change the format coordinates are displayed ++ Cambiar formato de coordenadas mostrado. ++ ++ ++ ++ Show Tool Help ++ Mostrar ayuda de la herramienta ++ ++ ++ ++ IOverlayCutMap ++ ++ ++ Form ++ ++ ++ ++ ++ Just move the map and zoom. ++ Solo mueve el mapa y zoom ++ ++ ++ ++ Add point to mask. ++ Añadir punto a la máscara. ++ ++ ++ ++ ++ ++ ++ ++ ++ ... ++ ++ ++ ++ ++ Move point of mask. ++ Mover punto de la máscara. ++ ++ ++ ++ Remove point from mask. ++ Borrar punto de la máscara. ++ ++ ++ ++ Remove complete cut mask. ++ Borrar máscara de corte completa. ++ ++ ++ ++ Load cut mask from shape file. ++ Cargar máscara de corte desde archivo Shape. ++ ++ ++ ++ Save cut mask to shape file. ++ Guardar máscara de corte en archivo Shape. ++ ++ ++ ++ IOverlayGridTool ++ ++ ++ Form ++ ++ ++ ++ ++ do not translate ++ No traducir ++ ++ ++ ++ IOverlayRefMap ++ ++ ++ Form ++ ++ ++ ++ ++ Just move the map and zoom. ++ Solo mover mapa y zoom. ++ ++ ++ ++ Add reference point. ++ Añadir punto de referencia. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ... ++ ++ ++ ++ ++ Move reference point. ++ Mover punto de referencia. ++ ++ ++ ++ Remove single reference point. ++ Borrar un punto de referencia. ++ ++ ++ ++ Move reference points with auto mode. This will pickup the next point after you moved a reference point. ++ Mover puntos de referencia con modo auto, captará el siguiente tras el desplazamiento del anterior. ++ ++ ++ ++ Remove all reference points. ++ Borrar todos los puntos de referencia. ++ ++ ++ ++ Switch to the Grid Tool. ++ Cambiar a la Herramienta de cuadrícula. ++ ++ ++ ++ Load reference points from GCP file. ++ Cargar puntos de referencia desde archivo GCP. ++ ++ ++ ++ Save reference points into GCP file. ++ Guardar puntos de referencia en archivo GCP. ++ ++ ++ ++ Sort list of reference points. ++ Ordenar lista de puntos de referencia ++ ++ ++ ++ (x, y)[pixel] ++ ++ ++ ++ ++ (lat, lon)[°] ++ ++ ++ ++ ++ TextLabel ++ ++ ++ ++ ++ Final Map Projection: ++ Proyección final del mapa: ++ ++ ++ ++ Enter a valid projection string. Valid strings are "+proj..." or "+init=epsg:...". ++ Introducir una cadena de proyección válida. Las cadenas válidas son "+proj..." o "+init=epsg:...". ++ ++ ++ ++ Start projection wizard. ++ Iniciar asistente de proyección. ++ ++ ++ ++ Delete ++ Borrar ++ ++ ++ ++ IProjWizard ++ ++ ++ Proj4 Wizard ++ Asistente de Proj4 ++ ++ ++ ++ Mercator ++ ++ ++ ++ ++ UTM ++ ++ ++ ++ ++ zone ++ zona ++ ++ ++ ++ user defined ++ definida por el usuario ++ ++ ++ ++ Datum ++ ++ ++ ++ ++ World Mercator (OSM) ++ ++ ++ ++ ++ Result: ++ Resultado: ++ ++ ++ ++ UPS North (North Pole) ++ UPS Norte (Polo Norte) ++ ++ ++ ++ UPS South (South Pole) ++ UPS Sur (Polo Sur) ++ ++ ++ ++ Projection ++ Proyección ++ ++ ++ ++ ISetupExtTools ++ ++ ++ Setup Ext. Tools ++ Configurar Herramientas Ext. ++ ++ ++ ++ ++ ++ ++ ++ ++ <b style='color: red;'>not found</b> ++ <b style='color: red;'>no encontrado</b> ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ... ++ ++ ++ ++ ++ gdal_translate: ++ ++ ++ ++ ++ gdalbuildvrt ++ ++ ++ ++ ++ gdaladdo: ++ ++ ++ ++ ++ gdalwarp: ++ ++ ++ ++ ++ ++ ++ ++ ++ Setup user defined path. ++ Configurar ruta definida por el usuario. ++ ++ ++ ++ qmt_rgb2pct ++ ++ ++ ++ ++ ++ ++ ++ ++ Reset user defined path setup. ++ Reiniciar la configuración de la ruta definida por el usuario. ++ ++ ++ ++ qmt_map2jnx ++ ++ ++ ++ ++ <b>Note:</b> Usually QMapTool should detect all external tools by itself. If it does not, it's a bad setup and you should fix the PATH variable of your system. You can setup the paths manually, too, if you know what you are doing. But please keep in mind that GDAL needs a proper environment setup to function properly. If it's not setup properly you might get results but these can be off grid. ++ <b>Nota:</b> QMapTool debería detectar todas las herramientas externas automáticamente, si no es así, es debido a una configuración errónea y hay que corregir la variable PATH del sistema. También se pueden configurar las rutas manualmente, si se sabe lo que se está haciendo, pero ten en cuenta que GDAL necesita una configuración del entorno adecuada para funcionar correctamente. Si no es correcta se pueden obtener resultados, pero pueden ser incorrectos. ++ ++ ++ ++ ITimeZoneSetup ++ ++ ++ Setup Time Zone ... ++ Configurar Zona Horaria... ++ ++ ++ ++ UTC ++ ++ ++ ++ ++ Local ++ ++ ++ ++ ++ Automatic ++ Automática ++ ++ ++ ++ Print date/time in ++ Mostrar fecha y hora en ++ ++ ++ ++ long format, or ++ formato largo o ++ ++ ++ ++ short format ++ formato corto ++ ++ ++ ++ IToolAddOverview ++ ++ ++ Form ++ ++ ++ ++ ++ do not translate ++ no traducir ++ ++ ++ ++ :2 ++ ++ ++ ++ ++ :4 ++ ++ ++ ++ ++ :8 ++ ++ ++ ++ ++ :16 ++ ++ ++ ++ ++ :32 ++ ++ ++ ++ ++ :64 ++ ++ ++ ++ ++ Remove all overview levels from map file. ++ Borrar los niveles de zoom del archivo del mapa. ++ ++ ++ ++ Remove ++ Borrar ++ ++ ++ ++ Do not copy the overviews into the file itself. Add them as external file. ++ No copiar los niveles de zoom en el mismo archivo, hacerlo en uno externo. ++ ++ ++ ++ Overview as external file ++ Niveles de zoom en archivo externo ++ ++ ++ ++ Start ++ Iniciar ++ ++ ++ ++ Cancel ++ Cancelar ++ ++ ++ ++ For all files ++ Para todos los archivos ++ ++ ++ ++ <b style='color: red;'>No "gdaladdo" found. Please check setup!</b> ++ <b style='color: red;'>"Gdaladdo" no encontrado. ¡Comprobar la configuración!</b> ++ ++ ++ ++ IToolCutMap ++ ++ ++ Form ++ ++ ++ ++ ++ do not translate ++ no traducir ++ ++ ++ ++ Output filename suffix ++ Sufijo del nombre de archivo resultante ++ ++ ++ ++ _cut ++ _cortar ++ ++ ++ ++ Create overviews for result. ++ Crear niveles de zoom. ++ ++ ++ ++ Start ++ Iniciar ++ ++ ++ ++ Cancel ++ Cancelar ++ ++ ++ ++ For all files ++ Para todos los archivos ++ ++ ++ ++ <b style='color: red;'>No "gdalwarp" found. Please check setup!</b> ++ lt;b style='color: red;'> "Gdalwarp"no encontrado. ¡Comprobar la configuración!</b> ++ ++ ++ ++ <b style='color: red;'>No "gdaladdo" found. Please check setup!</b> ++ <b style='color: red;'> "Gdaladdo"no encontrado ¡Comprobar la configuración!</b> ++ ++ ++ ++ IToolExport ++ ++ ++ Form ++ ++ ++ ++ ++ ++ do not translate ++ ++ ++ ++ ++ Garmin BirdsEye (*.jnx) ++ ++ ++ ++ ++ TwoNav Raster (*.rmap) ++ ++ ++ ++ ++ not implemented yet ++ Todavía no implementado ++ ++ ++ ++ Target File ++ Archivo de destino ++ ++ ++ ++ Start ++ Iniciar ++ ++ ++ ++ Cancel ++ Cancelar ++ ++ ++ ++ <b style='color: red;'>No "qmt_map2jnx" found. Please check setup!</b> ++ <b style='color: red;'>"qmt_map2jnx" No encontrado. ¡Comprobar la configuración!</b> ++ ++ ++ ++ Target Filename ++ Nombre del archivo de destino ++ ++ ++ ++ IToolExportJnx ++ ++ ++ Form ++ ++ ++ ++ ++ ++ BirdsEye ++ ++ ++ ++ ++ Product ID ++ ++ ++ ++ ++ Copyright notice ++ Aviso de copyright ++ ++ ++ ++ ++ None ++ Ninguno ++ ++ ++ ++ Product name ++ Nombre del producto ++ ++ ++ ++ Description ++ Descripción ++ ++ ++ ++ JPEG ++ ++ ++ ++ ++ Quality ++ Calidad ++ ++ ++ ++ Chroma subsampling ++ Submuestreo de Chroma ++ ++ ++ ++ 411 ++ ++ ++ ++ ++ 422 ++ ++ ++ ++ ++ 444 ++ ++ ++ ++ ++ Device ++ Dispositivo ++ ++ ++ ++ Z-Order ++ ++ ++ ++ ++ IToolGrid ++ ++ ++ Form ++ ++ ++ ++ ++ Grid Tool ++ Herramienta Cuadrícula ++ ++ ++ ++ do not translate ++ no traducir ++ ++ ++ ++ Ok ++ ++ ++ ++ ++ Cancel ++ Cancelar ++ ++ ++ ++ Reset ++ Reiniciar ++ ++ ++ ++ IToolOverviewGroupBox ++ ++ ++ GroupBox ++ ++ ++ ++ ++ :2 ++ ++ ++ ++ ++ :4 ++ ++ ++ ++ ++ :8 ++ ++ ++ ++ ++ :16 ++ ++ ++ ++ ++ :32 ++ ++ ++ ++ ++ :64 ++ ++ ++ ++ ++ Do not copy the overviews into the file itself. Add them as external file. ++ No copiar los niveles de zoom en el mismo archivo, hacerlo en uno externo. ++ ++ ++ ++ Overview as external file ++ Niveles de zoom en archivo externo ++ ++ ++ ++ IToolPalettize ++ ++ ++ Form ++ ++ ++ ++ ++ ++ do not translate ++ no traducir ++ ++ ++ ++ Single files, filename suffix ++ Archivos individuales, sufijo del nombre ++ ++ ++ ++ _8bit ++ ++ ++ ++ ++ Combined file, filename: ++ Archivo combinado, nombre: ++ ++ ++ ++ Embed result into *.vrt file. ++ Insertar el resultado en un archivo *.vrt. ++ ++ ++ ++ Create overviews for result. ++ Crear niveles de zoom. ++ ++ ++ ++ Start ++ Iniciar ++ ++ ++ ++ Cancel ++ Cancelar ++ ++ ++ ++ <b style='color: red;'>No "gdaladdo" found. Please check setup!</b> ++ <b style='color: red;'>"Gdaladdo" no encontrado. ¡Comprobar la configuración!</b> ++ ++ ++ ++ <b style='color: red;'>No "gdal_translate" found. Please check setup!</b> ++ <b style='color: red;'>"Gdal_translate" no encontrado. ¡Comprobar la configuración!</b> ++ ++ ++ ++ <b style='color: red;'>No "qmt_rgb2pct" found. Please check setup!</b> ++ <b style='color: red;'>"Qmt_rgb2pct" no encontrado. ¡Comprobar la configuración!</b> ++ ++ ++ ++ Select filename ++ Seleccionar nombre de archivo ++ ++ ++ ++ IToolRefMap ++ ++ ++ Form ++ ++ ++ ++ ++ do not translate ++ no traducir ++ ++ ++ ++ Output filename suffix ++ Sufijo del nombre de archivo ++ ++ ++ ++ _ref ++ ++ ++ ++ ++ Embed result into *.vrt file. ++ Insertar resultado en archivo *.vrt. ++ ++ ++ ++ Create overviews for result. ++ Crear niveles de zoom. ++ ++ ++ ++ Start ++ Iniciar ++ ++ ++ ++ Cancel ++ Cancelar ++ ++ ++ ++ For all files ++ Para todos los archivos ++ ++ ++ ++ <b style='color: red;'>No "gdalwarp" found. Please check setup!</b> ++ <b style='color: red;'>"Gdalwarp" no encontrado. ¡Comprobar la configuración!</b> ++ ++ ++ ++ <b style='color: red;'>No "gdal_translate" found. Please check setup!</b> ++ <b style='color: red;'>"Gdal_translate" no encontrado. ¡Comprobar la configuración!</b> ++ ++ ++ ++ <b style='color: red;'>No "gdaladdo" found. Please check setup!</b> ++ <b style='color: red;'>"Gdaladdo" no encontrado. ¡Comprobar la configuración!</b> ++ ++ ++ ++ IUnit ++ ++ ++ ++ Error ++ Error ++ ++ ++ ++ Bad position format. Must be: "[N|S] ddd mm.sss [W|E] ddd mm.sss" or "[N|S] ddd.ddd [W|E] ddd.ddd" ++ Formato de posición incorrecto. Debe ser: "[N|S] ddd mm.sss [W|E] ddd mm.sss" or "[N|S] ddd.ddd [W|E] ddd.ddd" ++ ++ ++ ++ Position values out of bounds. ++ Valores de posición fuera de los límites. ++ ++ ++ ++ IUnitsSetup ++ ++ ++ Setup units... ++ Configurar unidades... ++ ++ ++ ++ Nautical ++ Náutico ++ ++ ++ ++ Imperial ++ Imperial ++ ++ ++ ++ Metric ++ Métrico ++ ++ ++ ++ <b>Note:</b> For some GUI elements changing the units will not take effect until you restart QMapTool. ++ <b>Nota:</b> El cambio de las unidades de algunos elementos no se producirá hasta el reinicio de QMapTool. ++ ++ ++ +diff --git a/src/qmaptool/main.cpp b/src/qmaptool/main.cpp +new file mode 100644 +index 00000000..2d23b037 +--- /dev/null ++++ b/src/qmaptool/main.cpp +@@ -0,0 +1,76 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "CMainWindow.h" ++#include "CSingleInstanceProxy.h" ++#include "setup/IAppSetup.h" ++#include "version.h" ++ ++#include ++#include ++ ++int main(int argc, char ** argv) ++{ ++ QApplication app(argc, argv); ++ ++ QCoreApplication::setApplicationName("QMapTool"); ++ QCoreApplication::setOrganizationName("QLandkarte"); ++ QCoreApplication::setOrganizationDomain("qlandkarte.org"); ++ ++ IAppSetup& env = IAppSetup::createInstance(qApp); ++ env.processArguments(); ++ env.initLogHandler(); ++ env.initQMapTool(); ++ ++ // make sure this is the one and only instance on the system ++ CSingleInstanceProxy s(qlOpts->arguments); ++ ++ QSplashScreen *splash = nullptr; ++ if (!qlOpts->nosplash) ++ { ++ QPixmap pic(":/pic/splash.png"); ++ QPainter p(&pic); ++ QFont f = p.font(); ++ f.setBold(true); ++ ++ p.setPen(Qt::black); ++ p.setFont(f); ++ p.drawText(260,195,"QMapTool, V " VER_STR); ++ ++ splash = new QSplashScreen(pic); ++#ifdef Q_OS_MAC ++ // remove the splash screen flag on OS-X as workaround for the reported bug ++ // https://bugreports.qt.io/browse/QTBUG-49576 ++ splash->setWindowFlags(splash->windowFlags() & (~Qt::SplashScreen)); ++#endif ++ splash->show(); ++ } ++ ++ CMainWindow w; ++ w.show(); ++ ++ if(nullptr != splash) ++ { ++ splash->finish(&w); ++ delete splash; ++ } ++ ++ return app.exec(); ++} ++ ++ +diff --git a/src/qmaptool/overlay/COverlayCutMap.cpp b/src/qmaptool/overlay/COverlayCutMap.cpp +new file mode 100644 +index 00000000..ec64e12a +--- /dev/null ++++ b/src/qmaptool/overlay/COverlayCutMap.cpp +@@ -0,0 +1,644 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "canvas/IDrawContext.h" ++#include "helpers/CDraw.h" ++#include "helpers/CSettings.h" ++#include "items/CItemCutMap.h" ++#include "overlay/COverlayCutMap.h" ++ ++#include ++#include ++using std::bind; ++ ++static inline qreal sqr(qreal a) ++{ ++ return a*a; ++} ++ ++static inline qreal sqrlen(const QPointF &a) ++{ ++ return sqr(a.x()) + sqr(a.y()); ++} ++ ++ ++COverlayCutMap::COverlayCutMap(CItemCutMap *item, QStackedWidget *stackedWidget) ++ : IOverlay(stackedWidget) ++ , context(item->getDrawContext()) ++{ ++ setupUi(this); ++ ++ QFileInfo fi(item->getFilename()); ++ shapeFilename = fi.completeBaseName() + ".shp"; ++ ++ connect(toolNone, &QToolButton::clicked, this, bind(&COverlayCutMap::slotSetMode, this, eModeNone, std::placeholders::_1)); ++ connect(toolPointMove, &QToolButton::clicked, this, bind(&COverlayCutMap::slotSetMode, this, eModePointMove, std::placeholders::_1)); ++ connect(toolPointAdd, &QToolButton::clicked, this, bind(&COverlayCutMap::slotSetMode, this, eModePointAdd, std::placeholders::_1)); ++ connect(toolPointDel, &QToolButton::clicked, this, bind(&COverlayCutMap::slotSetMode, this, eModePointDel, std::placeholders::_1)); ++ connect(toolPointDelAll, &QToolButton::clicked, this, &COverlayCutMap::slotResetMask); ++ connect(toolLoadShape, &QToolButton::clicked, this, &COverlayCutMap::slotLoadShape); ++ connect(toolSaveShape, &QToolButton::clicked, this, &COverlayCutMap::slotSaveShape); ++} ++ ++void COverlayCutMap::saveSettings(QSettings& cfg) ++{ ++ cfg.setValue("region", region); ++} ++ ++void COverlayCutMap::loadSettings(QSettings& cfg) ++{ ++ region = (cfg.value("region", QPolygonF()).value()); ++ ++ updateGui(); ++} ++ ++ ++bool COverlayCutMap::drawFx(QPainter& p, CCanvas::redraw_e needsRedraw) ++{ ++ if(region.isEmpty()) ++ { ++ return true; ++ } ++ ++ QPolygonF shape = region; ++ context->convertMap2Screen(shape); ++ ++ if(shape.size() > 2) ++ { ++ QPainterPath path; ++ ++ QRectF rectMap = context->getMapArea(); ++ context->convertMap2Screen(rectMap); ++ ++ path.addRect(rectMap); ++ path.addPolygon(shape); ++ ++ p.setPen(QPen(Qt::darkBlue,1)); ++ ++ p.setBrush((idxFocus1 == NOIDX) ? Qt::BDiagPattern : Qt::NoBrush); ++ p.drawPath(path); ++ } ++ ++ QRectF dot1(0,0,5,5); ++ QRectF dot2(0,0,7,7); ++ const QPointF& pt1 = idxFocus1 != NOIDX ? shape[idxFocus1] : NOPOINTF; ++ const QPointF& pt2 = idxFocus2 != NOIDX ? shape[idxFocus2] : NOPOINTF; ++ ++ // draw black dots for each point in region ++ p.setPen(QPen(Qt::black, 1)); ++ p.setBrush(Qt::black); ++ for(const QPointF& pt : shape) ++ { ++ if(pt == pt1) ++ { ++ continue; ++ } ++ dot1.moveCenter(pt); ++ p.drawRect(dot1); ++ } ++ ++ // if just one dot is selected draw crosshair ++ if((idxFocus2 == NOIDX) && (idxFocus1 != NOIDX)) ++ { ++ CDraw::drawCrossHairDot(p, pt1); ++ } ++ else if((idxFocus2 != NOIDX) && (idxFocus1 == NOIDX)) ++ { ++ CDraw::drawCrossHairDot(p, pt2); ++ } ++ // if both points are selected highlight segment ++ else if((idxFocus2 != NOIDX) && (idxFocus1 != NOIDX)) ++ { ++ p.setPen(QPen(Qt::red, 2)); ++ p.setBrush(Qt::red); ++ ++ dot2.moveCenter(pt1); ++ p.drawRect(dot2); ++ dot2.moveCenter(pt2); ++ p.drawRect(dot2); ++ p.drawLine(pt1, pt2); ++ } ++ return true; ++} ++ ++void COverlayCutMap::mouseMoveEventFx(QMouseEvent *e) ++{ ++ QPointF pt = e->pos(); ++ context->convertScreen2Map(pt); ++ ++ switch(mode) ++ { ++ case eModePointMove: ++ mouseMovePointMove(pt); ++ break; ++ ++ case eModePointAdd: ++ mouseMovePointAdd(pt); ++ break; ++ ++ case eModePointDel: ++ mouseMovePointDel(pt); ++ break; ++ ++ default: ++ return; ++ } ++ ++ updateGui(); ++ context->triggerCompleteUpdate(CCanvas::eRedrawOverlay); ++} ++ ++void COverlayCutMap::mouseReleaseEventFx(QMouseEvent *e) ++{ ++ QPointF pt = e->pos(); ++ context->convertScreen2Map(pt); ++ ++ Qt::MouseButton button = e->button(); ++ ++ switch(mode) ++ { ++ case eModePointMove: ++ mouseReleasePointMove(pt, button); ++ break; ++ ++ case eModePointAdd: ++ mouseReleasePointAdd(pt, button); ++ break; ++ ++ case eModePointDel: ++ mouseReleasePointDel(pt, button); ++ break; ++ ++ default: ++ return; ++ } ++ ++ updateGui(); ++ context->triggerCompleteUpdate(CCanvas::eRedrawOverlay); ++} ++ ++QCursor COverlayCutMap::getCursorFx() ++{ ++ switch(mode) ++ { ++ case eModePointAdd: ++ return QCursor(QPixmap(":/cursors/cursorPointAdd.png"), 0, 0); ++ ++ case eModePointDel: ++ return QCursor(QPixmap(":/cursors/cursorPointDel.png"), 0, 0); ++ ++ case eModePointMove: ++ return QCursor(QPixmap(":/cursors/cursorPointMove.png"), 0, 0); ++ } ++ ++ return Qt::ArrowCursor; ++} ++ ++void COverlayCutMap::slotSetMode(mode_e m, bool on) ++{ ++ if(on) ++ { ++ mode = m; ++ } ++} ++ ++void COverlayCutMap::slotResetMask() ++{ ++ int res = QMessageBox::question(this, tr("Delete mask..."), tr("Are you sure to delete complete mask?"), QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes); ++ if(res != QMessageBox::Yes) ++ { ++ return; ++ } ++ ++ mouseReset(); ++ region.clear(); ++ storeToHistory(region); ++ updateGui(); ++} ++ ++void COverlayCutMap::slotSaveShape() ++{ ++ SETTINGS; ++ QString path = cfg.value("Path/shapeInput", QDir::homePath()).toString(); ++ ++ QString filename = QFileDialog::getSaveFileName(&CMainWindow::self(), tr("Save mask..."), path + "/" + shapeFilename, "Shape file (*.shp)"); ++ if(filename.isEmpty()) ++ { ++ return; ++ } ++ cfg.setValue("Path/shapeInput", QFileInfo(shapeFilename).absolutePath()); ++ ++ if(region.isEmpty()) ++ { ++ return; ++ } ++ shapeFilename = filename; ++ saveShape(filename); ++} ++ ++void COverlayCutMap::saveShape(const QString& filename) ++{ ++ const QPolygonF& line = region; ++ ++ QFile file(filename); ++ file.open(QIODevice::WriteOnly); ++ QTextStream out(&file); ++ ++ out << "id,WKT" << endl; ++ out << "1,\"POLYGON(("; ++ ++ bool first = true; ++ for(const QPointF& pt : line) ++ { ++ QPointF pt1 = pt; ++ context->convertMap2Coord(pt1); ++ ++ if(!first) ++ { ++ out << ", "; ++ } ++ first = false; ++ ++ out << qRound(pt1.x()) << " " << qRound(pt1.y()); ++ } ++ out << "))\"" << endl; ++} ++ ++void COverlayCutMap::slotLoadShape() ++{ ++ SETTINGS; ++ QString path = cfg.value("Path/shapeInput", QDir::homePath()).toString(); ++ ++ QString filename = QFileDialog::getOpenFileName(&CMainWindow::self(), tr("Load mask..."), path, "Shape file (*.shp)"); ++ if(filename.isEmpty()) ++ { ++ return; ++ } ++ cfg.setValue("Path/shapeInput", QFileInfo(filename).absolutePath()); ++ ++ QFile file(filename); ++ file.open(QIODevice::ReadOnly); ++ QTextStream in(&file); ++ ++ QString line = in.readLine().simplified(); ++ if(line != "id,WKT") ++ { ++ QMessageBox::warning(&CMainWindow::self(), tr("Failed..."), tr("Not a shape file."), QMessageBox::Abort); ++ return; ++ } ++ ++ while(!in.atEnd()) ++ { ++ QString line = in.readLine().simplified(); ++ if(line.startsWith("1,\"POLYGON((")) ++ { ++ region.clear(); ++ ++ line = line.mid(12); ++ QTextStream in2(&line, QIODevice::ReadOnly); ++ ++ while(!in2.atEnd()) ++ { ++ qreal x, y; ++ in2 >> x >> y; ++ ++ QPointF pt(x,y); ++ context->convertCoord2Map(pt); ++ ++ region << pt; ++ ++ QString str; ++ in2 >> str; ++ if(str != ",") ++ { ++ break; ++ } ++ } ++ } ++ } ++ ++ updateGui(); ++ context->triggerCompleteUpdate(CCanvas::eRedrawOverlay); ++ emit sigChanged(); ++} ++ ++void COverlayCutMap::mouseReset() ++{ ++ addPoint = false; ++ movePoint = false; ++ idxFocus1 = NOIDX; ++ idxFocus1 = NOIDX; ++} ++ ++void COverlayCutMap::abortStep() ++{ ++ if(addPoint) ++ { ++ restoreFromHistory(region); ++ addPoint = false; ++ idxFocus1 = NOIDX; ++ idxFocus2 = NOIDX; ++ } ++ else if(movePoint) ++ { ++ restoreFromHistory(region); ++ movePoint = false; ++ idxFocus1 = NOIDX; ++ } ++ ++ context->triggerCompleteUpdate(CCanvas::eRedrawOverlay); ++} ++ ++void COverlayCutMap::restoreFromHistory(QPolygonF& line) ++{ ++ line = history[idxHistory]; ++ emit sigChanged(); ++} ++ ++void COverlayCutMap::storeToHistory(const QPolygonF& line) ++{ ++ // crop history if necessary ++ if(idxHistory != NOIDX) ++ { ++ while(history.size() > (idxHistory + 1)) ++ { ++ history.pop_back(); ++ } ++ } ++ ++ history << line; ++ idxHistory = history.size() - 1; ++ ++ emit sigChanged(); ++} ++ ++void COverlayCutMap::isCloseTo(QPointF pt, QPolygonF line, qint32& idx) const ++{ ++ idx = NOIDX; ++ ++ context->convertMap2Screen(pt); ++ context->convertMap2Screen(line); ++ ++ if(line.isEmpty()) ++ { ++ return; ++ } ++ ++ qint32 min = 30; ++ const int N = region.size(); ++ for(int i = 0; i < N; i++) ++ { ++ qint32 d = (pt - line[i]).manhattanLength(); ++ if(d < min) ++ { ++ min = d; ++ idx = i; ++ } ++ } ++} ++ ++void COverlayCutMap::isCloseToLine(QPointF pt, QPolygonF line, qint32& idx1, qint32& idx2) const ++{ ++ idx1 = NOIDX; ++ idx2 = NOIDX; ++ ++ context->convertMap2Screen(pt); ++ context->convertMap2Screen(line); ++ ++ const int count = line.size(); ++ if(count < 2) ++ { ++ return; ++ } ++ ++ QPointF b = line[0]; ++ QPointF dbq = b - pt; ++ qreal dist = 30*30; ++ ++ for (qint32 i = 1; i < count; ++i) ++ { ++ const QPointF a = b; ++ const QPointF daq = dbq; ++ b = line[i]; ++ dbq = b - pt; ++ ++ const QPointF dab = a - b; ++ ++ const qreal inv_sqrlen = 1./sqrlen(dab); ++ const qreal t = (dab.x()*daq.x() + dab.y()*daq.y())*inv_sqrlen; ++ if (t < 0.) ++ { ++ continue; ++ } ++ qreal current_dist; ++ if (t <= 1.) ++ { ++ current_dist = sqr(dab.x()*dbq.y() - dab.y()*dbq.x())*inv_sqrlen; ++ } ++ else//t>1. ++ { ++ current_dist = sqrlen(dbq); ++ } ++ ++ if (current_dist < dist) ++ { ++ dist = current_dist; ++ idx1 = i - 1; ++ idx2 = i; ++ } ++ } ++} ++ ++ ++void COverlayCutMap::mouseMovePointAdd(const QPointF &pt) ++{ ++ if(region.isEmpty()) ++ { ++ return; ++ } ++ ++ if(addPoint) ++ { ++ region[idxFocus1] = pt; ++ } ++ else ++ { ++ // find line segment close to cursor ++ isCloseToLine(pt, region, idxFocus1, idxFocus2); ++ } ++} ++ ++void COverlayCutMap::mouseReleasePointAdd(const QPointF &pt, Qt::MouseButton button) ++{ ++ if(button == Qt::LeftButton) ++ { ++ if(addPoint) ++ { ++ // if isPoint is true the line has been appended/prepended ++ // in this case go on with adding another point ++ if(idxFocus1 == (region.size() - 1)) ++ { ++ idxFocus1++; ++ } ++ // store current state of line to undo/redo history ++ storeToHistory(region); ++ region.insert(idxFocus1, pt); ++ } ++ else if(idxFocus1 != NOIDX) ++ { ++ // add a new point to line segment ++ idxFocus2 = NOIDX; ++ idxFocus1++; ++ region.insert(idxFocus1, pt); ++ addPoint = true; ++ CCanvas::setOverrideCursor(Qt::BlankCursor, "COverlayCutMap::mouseReleasePointAdd"); ++ } ++ else if(region.isEmpty()) ++ { ++ region.append(pt); ++ storeToHistory(region); ++ region.append(pt); ++ region.append(pt); ++ idxFocus1 = 1; ++ addPoint = true; ++ CCanvas::setOverrideCursor(Qt::BlankCursor, "COverlayCutMap::mouseReleasePointAdd"); ++ } ++ } ++ else if(button == Qt::RightButton) ++ { ++ CCanvas::restoreOverrideCursor("COverlayCutMap::mouseReleasePointAdd"); ++ if(!addPoint) ++ { ++ toolNone->click(); ++ } ++ abortStep(); ++ } ++} ++ ++void COverlayCutMap::mouseMovePointDel(const QPointF &pt) ++{ ++ isCloseTo(pt, region, idxFocus1); ++} ++ ++void COverlayCutMap::mouseReleasePointDel(const QPointF &pt, Qt::MouseButton button) ++{ ++ if((idxFocus1 != NOIDX) && (button == Qt::LeftButton)) ++ { ++ //special case first or last point. ++ if((idxFocus1 == 0) || (idxFocus1 == (region.size() - 1))) ++ { ++ if(region.size() > 2) ++ { ++ // more than one point set ++ region.pop_back(); ++ region.pop_front(); ++ } ++ else ++ { ++ // remove last point ++ region.clear(); ++ } ++ ++ // close polygon area by appending the first point ++ if(!region.isEmpty()) ++ { ++ region << region.first(); ++ } ++ } ++ else ++ { ++ region.remove(idxFocus1); ++ } ++ storeToHistory(region); ++ } ++ else if(button == Qt::RightButton) ++ { ++ CCanvas::restoreOverrideCursor("COverlayCutMap::mouseReleasePointDel"); ++ toolNone->click(); ++ } ++ idxFocus1 = NOIDX; ++} ++ ++void COverlayCutMap::mouseMovePointMove(const QPointF &pt) ++{ ++ if(movePoint) ++ { ++ if((idxFocus1 == 0) || (idxFocus1 == (region.size() - 1))) ++ { ++ region.first() = pt; ++ region.last() = pt; ++ } ++ else ++ { ++ region[idxFocus1] = pt; ++ } ++ } ++ else ++ { ++ // no point selected yet, find point to highlight ++ isCloseTo(pt, region, idxFocus1); ++ } ++} ++ ++void COverlayCutMap::mouseReleasePointMove(const QPointF &pt, Qt::MouseButton button) ++{ ++ if(button == Qt::LeftButton) ++ { ++ if(movePoint) ++ { ++ // terminate moving the point ++ movePoint = false; ++ // store new state of line to undo/redo history ++ storeToHistory(region); ++ CCanvas::restoreOverrideCursor("COverlayCutMap::mouseReleasePointAdd"); ++ } ++ else if(idxFocus1 != NOIDX) ++ { ++ if((idxFocus1 == 0) || (idxFocus1 == (region.size() - 1))) ++ { ++ region.first() = pt; ++ region.last() = pt; ++ } ++ else ++ { ++ region[idxFocus1] = pt; ++ } ++ ++ movePoint = true; ++ CCanvas::setOverrideCursor(Qt::BlankCursor, "COverlayCutMap::mouseReleasePointMove"); ++ } ++ } ++ else if(button == Qt::RightButton) ++ { ++ CCanvas::restoreOverrideCursor("COverlayCutMap::mouseReleasePointMove"); ++ if(!movePoint) ++ { ++ toolNone->click(); ++ } ++ abortStep(); ++ } ++} ++ ++void COverlayCutMap::updateGui() ++{ ++ bool enable = !region.isEmpty(); ++ toolPointMove->setEnabled(enable); ++ toolPointDel->setEnabled(enable); ++ toolPointDelAll->setEnabled(enable); ++ toolSaveShape->setEnabled(enable); ++} +diff --git a/src/qmaptool/overlay/COverlayCutMap.h b/src/qmaptool/overlay/COverlayCutMap.h +new file mode 100644 +index 00000000..8938f006 +--- /dev/null ++++ b/src/qmaptool/overlay/COverlayCutMap.h +@@ -0,0 +1,105 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef COVERLAYCUTMAP_H ++#define COVERLAYCUTMAP_H ++ ++#include "canvas/CCanvas.h" ++#include "overlay/IOverlay.h" ++#include "ui_IOverlayCutMap.h" ++#include "units/IUnit.h" ++ ++ ++class QStackedWidget; ++class IDrawContext; ++class QSettings; ++class CItemCutMap; ++ ++class COverlayCutMap : public IOverlay, private Ui::IOverlayCutMap ++{ ++ Q_OBJECT ++public: ++ COverlayCutMap(CItemCutMap *item, QStackedWidget * stackedWidget); ++ virtual ~COverlayCutMap() = default; ++ ++ void saveSettings(QSettings& cfg); ++ void loadSettings(QSettings& cfg); ++ ++ bool drawFx(QPainter& p, CCanvas::redraw_e needsRedraw); ++ void mouseMoveEventFx(QMouseEvent *e); ++ void mouseReleaseEventFx(QMouseEvent *e); ++ QCursor getCursorFx(); ++ ++ void abortStep(); ++ ++ enum mode_e ++ { ++ eModeNone ++ ,eModePointMove ++ ,eModePointAdd ++ ,eModePointDel ++ }; ++ ++ void saveShape(const QString& filename); ++ ++ bool isOk() const ++ { ++ return !region.isEmpty(); ++ } ++ ++private slots: ++ void slotSetMode(mode_e m, bool on); ++ void slotResetMask(); ++ void slotSaveShape(); ++ void slotLoadShape(); ++ ++private: ++ void restoreFromHistory(QPolygonF& line); ++ void storeToHistory(const QPolygonF& line); ++ void isCloseTo(QPointF pt, QPolygonF line, qint32& idx) const; ++ void isCloseToLine(QPointF pt, QPolygonF line, qint32 &idx1, qint32 &idx2) const; ++ void mouseReset(); ++ ++ void mouseMovePointAdd(const QPointF &pt); ++ void mouseMovePointDel(const QPointF &pt); ++ void mouseMovePointMove(const QPointF &pt); ++ ++ void mouseReleasePointAdd(const QPointF &pt, Qt::MouseButton button); ++ void mouseReleasePointDel(const QPointF &pt, Qt::MouseButton button); ++ void mouseReleasePointMove(const QPointF &pt, Qt::MouseButton button); ++ ++ void updateGui(); ++ ++ IDrawContext* context; ++ ++ mode_e mode = eModeNone; ++ QPolygonF region; ++ ++ qint32 idxFocus1 = NOIDX; ++ qint32 idxFocus2 = NOIDX; ++ bool addPoint = false; ++ bool movePoint = false; ++ ++ QList history; ++ qint32 idxHistory = NOIDX; ++ ++ QString shapeFilename; ++}; ++ ++#endif //COVERLAYCUTMAP_H ++ +diff --git a/src/qmaptool/overlay/COverlayGridTool.cpp b/src/qmaptool/overlay/COverlayGridTool.cpp +new file mode 100644 +index 00000000..7a0fa26e +--- /dev/null ++++ b/src/qmaptool/overlay/COverlayGridTool.cpp +@@ -0,0 +1,348 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "canvas/IDrawContext.h" ++#include "CMainWindow.h" ++#include "helpers/CSettings.h" ++#include "items/CItemRefMap.h" ++#include "overlay/COverlayGridTool.h" ++#include "overlay/refmap/COverlayRefMapPoint.h" ++#include "overlay/refmap/CProjWizard.h" ++ ++#include ++#include ++ ++COverlayGridTool::COverlayGridTool(QWidget *parent) ++ : QWidget(parent) ++{ ++ setupUi(this); ++ labelFinal->setText(tr("Before you proceed with 'ok':\n" ++ "Please cross check all data once again. A bad reference coordinate will ruin " ++ "all the work. Also cross check if the selected area contains as many reference " ++ "points as possible at the border. You can easily delete points outside the map " ++ "in the Reference Tool. But it's much more effort to set additional points in " ++ "case you miss some. When you are done press 'ok' to transfer the derived " ++ "reference points to the Reference Tool.\n\n" ++ "The next step will be to use the Reference Tool to adjust the position of all " ++ "reference points to the real grid position on the map.")); ++ ++ connect(CMainWindow::self().showToolHelp(), &QAction::toggled, labelFinal, &QLabel::setVisible); ++ ++ QButtonGroup * group = new QButtonGroup(this); ++ group->addButton(radioSetRef); ++ group->addButton(radioGridPlacer); ++ group->addButton(radioSelectArea); ++ ++ ++ connect(radioSetRef, &QRadioButton::toggled, widgetSetRef, &QFrame::setEnabled); ++ connect(radioGridPlacer, &QRadioButton::toggled, widgetGridPlacer, &CGridPlacer::setEnabled); ++ connect(radioSelectArea, &QRadioButton::toggled, widgetSelectArea, &QLabel::setEnabled); ++ ++ ++ connect(widgetSetRef, &CGridSetRef::sigChanged, this, &COverlayGridTool::slotCalculate); ++ connect(widgetSetRef, &CGridSetRef::sigChanged, this, &COverlayGridTool::slotCheckInput); ++ ++ connect(widgetGridPlacer, &CGridPlacer::sigChanged, this, &COverlayGridTool::slotCheckInput); ++ connect(widgetGridPlacer, &CGridPlacer::sigSetArea, this, &COverlayGridTool::slotSetArea); ++ connect(widgetGridPlacer, &CGridPlacer::sigChanged, this, &COverlayGridTool::slotCalculate); ++ ++ connect(widgetSelectArea, &CGridSelArea::sigChanged, this, &COverlayGridTool::slotCalculate); ++ connect(widgetSelectArea, &CGridSelArea::sigChanged, this, &COverlayGridTool::slotCheckInput); ++} ++ ++void COverlayGridTool::slotReset() ++{ ++ widgetSetRef->slotReset(); ++ widgetGridPlacer->slotReset(); ++ widgetSelectArea->slotReset(); ++ ++ radioSetRef->setChecked(true); ++ ++ SETTINGS; ++ cfg.beginGroup("GridTool"); ++ cfg.remove(""); ++ cfg.endGroup(); ++ cfg.sync(); ++} ++ ++void COverlayGridTool::registerItem(CItemRefMap * item) ++{ ++ this->item = item; ++ if(item != nullptr) ++ { ++ context = item->getDrawContext(); ++ if(context == nullptr) ++ { ++ this->item = nullptr; ++ } ++ } ++ else ++ { ++ context = nullptr; ++ } ++ ++ ++ widgetGridPlacer->registerItem(this->item); ++ widgetSelectArea->registerItem(this->item); ++ ++ radioSetRef->setChecked(true); ++ ++ SETTINGS; ++ cfg.beginGroup("GridTool"); ++ if(this->item != nullptr) ++ { ++ widgetSetRef->loadSettings(cfg); ++ widgetGridPlacer->loadSettings(cfg); ++ widgetSelectArea->loadSettings(cfg); ++ } ++ else ++ { ++ cfg.remove(""); ++ ++ widgetSetRef->saveSettings(cfg); ++ widgetGridPlacer->saveSettings(cfg); ++ widgetSelectArea->saveSettings(cfg); ++ } ++ cfg.endGroup(); ++ ++ slotCheckInput(); ++} ++ ++ ++void COverlayGridTool::slotCheckInput() ++{ ++ bool group1Ok = widgetSetRef->isOk(); ++ radioGridPlacer->setEnabled(group1Ok); ++ ++ bool group2Ok = widgetGridPlacer->isOk(); ++ radioSelectArea->setEnabled(group2Ok&& group1Ok); ++ ++ const QPointF& p1 = widgetGridPlacer->getPoint(0); ++ const QPointF& p2 = widgetGridPlacer->getPoint(1); ++ const QPointF& p3 = widgetGridPlacer->getPoint(2); ++ const QPointF& p4 = widgetGridPlacer->getPoint(3); ++ const QRectF& area = widgetSelectArea->getArea(); ++ ++ bool group3Ok = true; ++ group3Ok &= !area.isEmpty(); ++ group3Ok &= area.isValid(); ++ group3Ok &= !area.isNull(); ++ group3Ok &= area.contains(p1); ++ group3Ok &= area.contains(p2); ++ group3Ok &= area.contains(p3); ++ group3Ok &= area.contains(p4); ++ ++ labelFinal->setEnabled(group1Ok && group2Ok && group3Ok); ++ ++ emit sigChanged(group1Ok && group2Ok && group3Ok); ++} ++ ++bool COverlayGridTool::drawFx(QPainter& p, CCanvas::redraw_e needsRedraw) ++{ ++ if(radioSelectArea->isEnabled()) ++ { ++ widgetSelectArea->drawFx(p, needsRedraw); ++ ++ QRectF dot1(0,0,7,7); ++ p.setPen(QPen(Qt::white, 1)); ++ p.setBrush(Qt::darkGreen); ++ ++ for(COverlayRefMapPoint * point : refPoints) ++ { ++ QPointF pt = point->getPtPtx(); ++ context->convertMap2Screen(pt); ++ dot1.moveCenter(pt); ++ p.drawRect(dot1); ++ } ++ } ++ ++ widgetGridPlacer->drawFx(p, needsRedraw); ++ return false; ++} ++ ++void COverlayGridTool::mouseMoveEventFx(QMouseEvent *e) ++{ ++ if(radioGridPlacer->isChecked()) ++ { ++ widgetGridPlacer->mouseMoveEventFx(e); ++ } ++ else if(radioSelectArea->isChecked()) ++ { ++ widgetSelectArea->mouseMoveEventFx(e); ++ } ++} ++ ++void COverlayGridTool::mouseReleaseEventFx(QMouseEvent *e) ++{ ++ if(radioGridPlacer->isChecked()) ++ { ++ widgetGridPlacer->mouseReleaseEventFx(e); ++ } ++ else if(radioSelectArea->isChecked()) ++ { ++ widgetSelectArea->mouseReleaseEventFx(e); ++ } ++} ++ ++void COverlayGridTool::leaveEventFx(QEvent *e) ++{ ++ if(radioGridPlacer->isChecked()) ++ { ++ widgetGridPlacer->leaveEventFx(e); ++ } ++ else if(radioSelectArea->isChecked()) ++ { ++ widgetSelectArea->leaveEventFx(e); ++ } ++} ++ ++QCursor COverlayGridTool::getCursorFx() ++{ ++ if(radioGridPlacer->isChecked()) ++ { ++ return widgetGridPlacer->getCursorFx(); ++ } ++ else if(radioSelectArea->isChecked()) ++ { ++ return widgetSelectArea->getCursorFx(); ++ } ++ else ++ { ++ return Qt::ArrowCursor; ++ } ++} ++ ++ ++void COverlayGridTool::slotSetArea(const QRectF& rect) ++{ ++ qreal hspace = rect.width() / 2; ++ qreal vspace = rect.height() / 2; ++ QRectF area = rect; ++ ++ area.setTopLeft(rect.topLeft() - QPointF(hspace, vspace)); ++ area.setBottomRight(rect.bottomRight() + QPointF(hspace, vspace)); ++ ++ widgetSelectArea->slotSetArea(area); ++ radioSelectArea->setChecked(true); ++} ++ ++void COverlayGridTool::slotCalculate() ++{ ++ if(!radioSelectArea->isEnabled()) ++ { ++ return; ++ } ++ ++ qDeleteAll(refPoints); ++ refPoints.clear(); ++ ++ projPJ pjsrc = pj_init_plus(widgetSetRef->getProjection().toLatin1()); ++ if(pjsrc == nullptr) ++ { ++ return; ++ } ++ ++ projPJ pjtar = pj_init_plus("+proj=longlat +datum=WGS84 +no_defs"); ++ if(pjtar == nullptr) ++ { ++ pj_free(pjsrc); ++ return; ++ } ++ ++ const QRectF& area = widgetSelectArea->getArea(); ++ ++ const QPointF& ptTopLeft = widgetGridPlacer->getPoint(0); ++ const QPointF& ptTopRight = widgetGridPlacer->getPoint(1); ++ const QPointF& ptBottomRight = widgetGridPlacer->getPoint(2); ++ const QPointF& ptBottomLeft = widgetGridPlacer->getPoint(3); ++ ++ qreal dx11 = ptTopRight.x() - ptTopLeft.x(); ++ qreal dy11 = ptTopRight.y() - ptTopLeft.y(); ++ qreal dx12 = ptBottomRight.x() - ptBottomLeft.x(); ++ qreal dy12 = ptBottomRight.y() - ptBottomLeft.y(); ++ qreal dx1 = (dx11 + dx12) / 2; ++ qreal dy1 = (dy11 + dy12) / 2; ++ ++ qreal alpha = qAtan(dy1/dx1); ++ qreal distx = qSqrt(dx1*dx1 + dy1*dy1); ++ ++ qreal dx21 = ptBottomLeft.x() - ptTopLeft.x(); ++ qreal dy21 = ptBottomLeft.y() - ptTopLeft.y(); ++ qreal dx22 = ptBottomRight.x() - ptTopRight.x(); ++ qreal dy22 = ptBottomRight.y() - ptTopRight.y(); ++ qreal dx2 = (dx21 + dx22) / 2; ++ qreal dy2 = (dy21 + dy22) / 2; ++ ++ qreal disty = qSqrt(dx2*dx2 + dy2*dy2); ++ ++ QMatrix translationMatrix(1, 0, 0, 1, ptTopLeft.x(), ptTopLeft.y()); ++ QMatrix rotationMatrix(qCos(alpha), qSin(alpha), -qSin(alpha), qCos(alpha), 0, 0); ++ QMatrix scalingMatrix(distx, 0, 0, disty, 0, 0); ++ ++ // forward matrix index -> map pixel coord ++ QMatrix mxFwd = scalingMatrix * rotationMatrix * translationMatrix; ++ // backward matrix map pixel coord -> index ++ QMatrix mxBwd = mxFwd.inverted(); ++ ++ QPointF tl = mxBwd.map(area.topLeft()); ++ QPointF br = mxBwd.map(area.bottomRight()); ++ ++ int xMin = qCeil(tl.x()) - 1; ++ int yMin = qCeil(tl.y()) - 1; ++ ++ int xMax = qCeil(br.x()) + 1; ++ int yMax = qCeil(br.y()) + 1; ++ ++ qreal lonRef = widgetSetRef->getEasting(); ++ qreal latRef = widgetSetRef->getNorthing(); ++ qreal dLon = widgetSetRef->getHorizSpacing(); ++ qreal dLat = widgetSetRef->getVertSpacing(); ++ ++ bool isLonLat = pj_is_latlong(pjsrc); ++ ++ for(int y = yMin; y < yMax; y++) ++ { ++ for(int x = xMin; x < xMax; x++) ++ { ++ QPointF ptPtx = mxFwd.map(QPointF(x,y)); ++ if(area.contains(ptPtx)) ++ { ++ ptPtx.rx() = qRound(ptPtx.x()); ++ ptPtx.ry() = qRound(ptPtx.y()); ++ ++ qreal lat = latRef - y * dLat; ++ qreal lon = lonRef + x * dLon; ++ ++ if(isLonLat) ++ { ++ lon *= DEG_TO_RAD; ++ lat *= DEG_TO_RAD; ++ } ++ ++ pj_transform(pjsrc, pjtar, 1, 0, &lon, &lat, 0); ++ lon *= RAD_TO_DEG; ++ lat *= RAD_TO_DEG; ++ ++ refPoints << new COverlayRefMapPoint(0, QPointF(lon,lat), ptPtx, nullptr); ++ } ++ } ++ } ++ ++ pj_free(pjsrc); ++ pj_free(pjtar); ++} +diff --git a/src/qmaptool/overlay/COverlayGridTool.h b/src/qmaptool/overlay/COverlayGridTool.h +new file mode 100644 +index 00000000..f50b22f1 +--- /dev/null ++++ b/src/qmaptool/overlay/COverlayGridTool.h +@@ -0,0 +1,68 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef COVERLAYGRIDTOOL_H ++#define COVERLAYGRIDTOOL_H ++ ++#include "canvas/CCanvas.h" ++#include "ui_IOverlayGridTool.h" ++ ++class CItemRefMap; ++class COverlayRefMapPoint; ++ ++class COverlayGridTool : public QWidget, private Ui::IOverlayGridTool ++{ ++ Q_OBJECT ++public: ++ COverlayGridTool(QWidget * parent); ++ virtual ~COverlayGridTool() = default; ++ ++ bool drawFx(QPainter& p, CCanvas::redraw_e needsRedraw); ++ void mouseMoveEventFx(QMouseEvent *e); ++ void mouseReleaseEventFx(QMouseEvent *e); ++ void leaveEventFx(QEvent *e); ++ QCursor getCursorFx(); ++ ++ void registerItem(CItemRefMap * item); ++ ++ QList& getRefPoints() ++ { ++ return refPoints; ++ } ++ ++signals: ++ void sigChanged(bool ok); ++ ++public slots: ++ void slotReset(); ++ ++private slots: ++ void slotCheckInput(); ++ void slotSetArea(const QRectF& rect); ++ void slotCalculate(); ++ ++private: ++ ++ CItemRefMap * item = nullptr; ++ const IDrawContext * context = nullptr; ++ ++ QList refPoints; ++}; ++ ++#endif //COVERLAYGRIDTOOL_H ++ +diff --git a/src/qmaptool/overlay/COverlayRefMap.cpp b/src/qmaptool/overlay/COverlayRefMap.cpp +new file mode 100644 +index 00000000..0afc882c +--- /dev/null ++++ b/src/qmaptool/overlay/COverlayRefMap.cpp +@@ -0,0 +1,747 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "canvas/IDrawContext.h" ++#include "helpers/CDraw.h" ++#include "helpers/CSettings.h" ++#include "items/CItemRefMap.h" ++#include "overlay/COverlayRefMap.h" ++#include "overlay/refmap/CDialogRefPoint.h" ++#include "overlay/refmap/COverlayRefMapPoint.h" ++#include "overlay/refmap/CProjWizard.h" ++ ++#include ++#include ++using std::bind; ++ ++COverlayRefMap::COverlayRefMap(CItemRefMap *item, QStackedWidget *stackedWidget) ++ : IOverlay(stackedWidget) ++ , context(item->getDrawContext()) ++ , item(item) ++{ ++ setupUi(this); ++ ++ QFileInfo fi(item->getFilename()); ++ gcpFilename = fi.completeBaseName() + ".gcp"; ++ ++ labelHelp->setText(tr("If you used the Grid Tool you have to fine tune the reference points by placing them " ++ "as much as possible on the grid crossing. Be aware that if you over scale you get " ++ "jumping points by rounding effects. Be precise but do not make religion out " ++ "of the task.\nIf your mouse focus is on the map you can use the N and B keys to " ++ "jump forward an backward in the reference point list. " ++ "\nThe is also the option to fine tune the reference points in auto-mode. In this " ++ "mode the next reference point is selected automatically right after you placed the " ++ "current one. This is very convenient for a large number of reference points.")); ++ ++ labelHelp->setVisible(CMainWindow::self().showToolHelp()->isChecked()); ++ connect(CMainWindow::self().showToolHelp(), &QAction::toggled, labelHelp, &QLabel::setVisible); ++ ++ treeWidget->addAction(actionDelRefPoint); ++ ++ connect(toolNone, &QToolButton::clicked, this, bind(&COverlayRefMap::slotSetMode, this, eModeNone, std::placeholders::_1)); ++ connect(toolRefMove, &QToolButton::clicked, this, bind(&COverlayRefMap::slotSetMode, this, eModePointMove, std::placeholders::_1)); ++ connect(toolRefAdd, &QToolButton::clicked, this, bind(&COverlayRefMap::slotSetMode, this, eModePointAdd, std::placeholders::_1)); ++ connect(toolRefDel, &QToolButton::clicked, this, bind(&COverlayRefMap::slotSetMode, this, eModePointDel, std::placeholders::_1)); ++ connect(toolRefMoveAuto, &QToolButton::clicked, this, bind(&COverlayRefMap::slotSetMode, this, eModePointMoveAuto, std::placeholders::_1)); ++ connect(toolRefDelAll, &QToolButton::clicked, this, &COverlayRefMap::slotResetRef); ++ connect(toolLoadGcp, &QToolButton::clicked, this, &COverlayRefMap::slotLoadGcp); ++ connect(toolSaveGcp, &QToolButton::clicked, this, &COverlayRefMap::slotSaveGcp); ++ connect(toolProjection, &QToolButton::clicked, this, &COverlayRefMap::slotProjWizard); ++ connect(toolGridTool, &QToolButton::clicked, this, &COverlayRefMap::slotGridTool); ++ connect(toolSort, &QToolButton::clicked, this, &COverlayRefMap::slotSortRefPoints); ++ connect(treeWidget, &QTreeWidget::itemSelectionChanged, this, &COverlayRefMap::slotSelectionChanged); ++ connect(actionDelRefPoint, &QAction::triggered, this, &COverlayRefMap::slotDelRefPoints); ++} ++ ++void COverlayRefMap::saveSettings(QSettings& cfg) ++{ ++ QByteArray buffer; ++ QDataStream stream(&buffer, QIODevice::WriteOnly); ++ stream.setByteOrder(QDataStream::LittleEndian); ++ stream.setVersion(QDataStream::Qt_5_4); ++ ++ const int N = treeWidget->topLevelItemCount(); ++ stream << N; ++ for(int n = 0; n < N; n++) ++ { ++ COverlayRefMapPoint * item = dynamic_cast(treeWidget->topLevelItem(n)); ++ if(item != nullptr) ++ { ++ stream << item->getPtPtx() << item->getPtRef(); ++ } ++ } ++ ++ cfg.beginGroup("grid"); ++ cfg.setValue("points", buffer); ++ cfg.setValue("projection", lineProjection->text()); ++ cfg.endGroup(); ++} ++ ++void COverlayRefMap::loadSettings(QSettings& cfg) ++{ ++ QByteArray buffer; ++ cfg.beginGroup("grid"); ++ buffer = cfg.value("points", buffer).toByteArray(); ++ lineProjection->setText(cfg.value("projection", "").toString()); ++ lineProjection->setCursorPosition(0); ++ cfg.endGroup(); ++ ++ QDataStream stream(&buffer, QIODevice::ReadOnly); ++ stream.setByteOrder(QDataStream::LittleEndian); ++ stream.setVersion(QDataStream::Qt_5_4); ++ ++ ++ int N; ++ stream >> N; ++ for(int n = 0; n < N; n++) ++ { ++ QPointF ptPtx; ++ QPointF ptRef; ++ stream >> ptPtx >> ptRef; ++ new COverlayRefMapPoint(n+1, ptRef, ptPtx, treeWidget); ++ } ++ ++ updateGui(); ++ slotSortRefPoints(); ++ emit sigChanged(); ++} ++ ++void COverlayRefMap::slotSortRefPoints() ++{ ++ treeWidget->sortItems(0, Qt::AscendingOrder); ++ const int N = treeWidget->topLevelItemCount(); ++ for(int n = 0; n < N; n++) ++ { ++ COverlayRefMapPoint * point = dynamic_cast(treeWidget->topLevelItem(n)); ++ if(point == nullptr) ++ { ++ continue; ++ } ++ ++ point->setIndex(n); ++ } ++ ++ treeWidget->header()->resizeSections(QHeaderView::ResizeToContents); ++} ++ ++void COverlayRefMap::addRefPoints(QList& points) ++{ ++ // it's faster to use a bulk add ++ QList items; ++ for(QTreeWidgetItem * item : points) ++ { ++ items << item; ++ } ++ treeWidget->addTopLevelItems(items); ++ ++ // as the tree widget owns the items now, the list has to be cleared ++ points.clear(); ++ // reflect changes on the GUI ++ updateGui(); ++ ++ emit sigChanged(); ++} ++ ++QString COverlayRefMap::getMapProjection() const ++{ ++ return lineProjection->text(); ++} ++ ++const QList COverlayRefMap::getRefPoints() const ++{ ++ QList points; ++ ++ const int N = treeWidget->topLevelItemCount(); ++ for(int n = 0; n < N; n++) ++ { ++ COverlayRefMapPoint * item = dynamic_cast(treeWidget->topLevelItem(n)); ++ if(item != nullptr) ++ { ++ points << item; ++ } ++ } ++ ++ return points; ++} ++ ++bool COverlayRefMap::drawFx(QPainter& p, CCanvas::redraw_e needsRedraw) ++{ ++ QRectF dot1(0,0,5,5); ++ const int N = treeWidget->topLevelItemCount(); ++ for(int n = 0; n < N; n++) ++ { ++ COverlayRefMapPoint * item = dynamic_cast(treeWidget->topLevelItem(n)); ++ if(item != nullptr) ++ { ++ if(item->isSelected()) ++ { ++ p.setPen(QPen(Qt::red, 1)); ++ p.setBrush(Qt::red); ++ } ++ else ++ { ++ p.setPen(QPen(Qt::black, 1)); ++ p.setBrush(Qt::black); ++ } ++ ++ QPointF pt = item->getPtPtx(); ++ if((pt - ptFocus1).manhattanLength() > 30) ++ { ++ context->convertMap2Screen(pt); ++ dot1.moveCenter(pt); ++ p.drawRect(dot1); ++ } ++ } ++ } ++ ++ QPointF pt = NOPOINTF; ++ if(ptFocus2 != NOPOINTF) ++ { ++ pt = ptFocus2; ++ } ++ else if(ptFocus1 != NOPOINTF) ++ { ++ pt = ptFocus1; ++ } ++ ++ ++ if(pt != NOPOINTF) ++ { ++ context->convertMap2Screen(pt); ++ ++ if(movePoint) ++ { ++ QPointF pt1 = ptFocus1; ++ context->convertMap2Screen(pt1); ++ ++ p.setPen(QPen(Qt::red, 1)); ++ p.setBrush(Qt::red); ++ p.drawLine(pt1, pt); ++ dot1.moveCenter(pt1); ++ p.drawRect(dot1); ++ } ++ ++ CDraw::drawCrossHairDot(p, pt); ++ } ++ ++ ++ return true; ++} ++ ++QPointF COverlayRefMap::isCloseTo(QPointF pt) ++{ ++ qint32 min = 30; ++ COverlayRefMapPoint * selItem = nullptr; ++ ++ context->convertMap2Screen(pt); ++ ++ const int N = treeWidget->topLevelItemCount(); ++ for(int n = 0; n < N; n++) ++ { ++ COverlayRefMapPoint * item = dynamic_cast(treeWidget->topLevelItem(n)); ++ if(item == nullptr) ++ { ++ continue; ++ } ++ ++ QPointF ptx = item->getPtPtx(); ++ context->convertMap2Screen(ptx); ++ ++ qint32 d = (pt - ptx).manhattanLength(); ++ if(d < min) ++ { ++ min = d; ++ selItem = item; ++ } ++ } ++ ++ if(selItem != nullptr) ++ { ++ treeWidget->setCurrentItem(selItem); ++ return selItem->getPtPtx(); ++ } ++ else ++ { ++ return NOPOINTF; ++ } ++} ++ ++ ++void COverlayRefMap::mouseMoveEventFx(QMouseEvent *e) ++{ ++ QPointF pt = e->pos(); ++ context->convertScreen2Map(pt); ++ ++ switch(mode) ++ { ++ case eModePointMove: ++ case eModePointMoveAuto: ++ mouseMovePointMove(pt); ++ break; ++ ++ case eModePointAdd: ++ mouseMovePointAdd(pt); ++ break; ++ ++ case eModePointDel: ++ mouseMovePointDel(pt); ++ break; ++ } ++ ++ updateGui(); ++ context->triggerCompleteUpdate(CCanvas::eRedrawOverlay); ++} ++ ++void COverlayRefMap::mouseReleaseEventFx(QMouseEvent *e) ++{ ++ QPointF pt = e->pos(); ++ context->convertScreen2Map(pt); ++ ++ Qt::MouseButton button = e->button(); ++ ++ switch(mode) ++ { ++ case eModePointMove: ++ case eModePointMoveAuto: ++ mouseReleasePointMove(pt, button); ++ break; ++ ++ case eModePointAdd: ++ mouseReleasePointAdd(pt, button); ++ break; ++ ++ case eModePointDel: ++ mouseReleasePointDel(pt, button); ++ break; ++ } ++ ++ updateGui(); ++ context->triggerCompleteUpdate(CCanvas::eRedrawOverlay); ++} ++ ++void COverlayRefMap::mouseMovePointAdd(const QPointF &pt) ++{ ++ ptFocus1 = pt; ++} ++ ++void COverlayRefMap::mouseMovePointDel(const QPointF &pt) ++{ ++ ptFocus1 = isCloseTo(pt); ++} ++ ++void COverlayRefMap::mouseMovePointMove(const QPointF &pt) ++{ ++ if(movePoint) ++ { ++ ptFocus2 = pt; ++ } ++ else ++ { ++ ptFocus1 = isCloseTo(pt); ++ } ++} ++ ++void COverlayRefMap::mouseReleasePointAdd(const QPointF &pt, Qt::MouseButton button) ++{ ++ if(button == Qt::LeftButton) ++ { ++ QPointF ptPtx = pt; ++ QPointF ptRef = NOPOINTF; ++ // ask for coordinate ++ CDialogRefPoint dlg(ptPtx, ptRef, this); ++ int res = dlg.exec(); ++ if(res == QDialog::Accepted) ++ { ++ new COverlayRefMapPoint(treeWidget->topLevelItemCount() + 1, ptRef, ptPtx, treeWidget); ++ emit sigChanged(); ++ } ++ } ++ else if(button == Qt::RightButton) ++ { ++ abortStep(); ++ toolNone->click(); ++ CCanvas::restoreOverrideCursor("CRefMapGrid::mouseReleasePointAdd"); ++ } ++} ++ ++void COverlayRefMap::mouseReleasePointDel(const QPointF &pt, Qt::MouseButton button) ++{ ++ if(button == Qt::LeftButton) ++ { ++ if(ptFocus1 == NOPOINTF) ++ { ++ return; ++ } ++ ++ const int N = treeWidget->topLevelItemCount(); ++ for(int n = 0; n < N; n++) ++ { ++ COverlayRefMapPoint * item = dynamic_cast(treeWidget->topLevelItem(n)); ++ if(item == nullptr) ++ { ++ continue; ++ } ++ ++ if(item->getPtPtx() == ptFocus1) ++ { ++ delete item; ++ abortStep(); ++ emit sigChanged(); ++ return; ++ } ++ } ++ } ++ else if(button == Qt::RightButton) ++ { ++ CCanvas::restoreOverrideCursor("CRefMapGrid::mouseReleasePointDel"); ++ toolNone->click(); ++ abortStep(); ++ } ++} ++ ++void COverlayRefMap::mouseReleasePointMove(const QPointF &pt, Qt::MouseButton button) ++{ ++ if(button == Qt::LeftButton) ++ { ++ if(movePoint) ++ { ++ const int N = treeWidget->topLevelItemCount(); ++ for(int n = 0; n < N; n++) ++ { ++ COverlayRefMapPoint * item = dynamic_cast(treeWidget->topLevelItem(n)); ++ if(item == nullptr) ++ { ++ continue; ++ } ++ ++ if(item->getPtPtx() == ptFocus1) ++ { ++ item->setPtPtx(pt); ++ break; ++ } ++ } ++ ++ switch(mode) ++ { ++ case eModePointMove: ++ { ++ abortStep(); ++ CCanvas::restoreOverrideCursor("CRefMapGrid::mouseReleasePointMove"); ++ break; ++ } ++ ++ case eModePointMoveAuto: ++ { ++ int idx = treeWidget->indexOfTopLevelItem(treeWidget->currentItem()) + 1; ++ if(idx >= treeWidget->topLevelItemCount()) ++ { ++ abortStep(); ++ CCanvas::restoreOverrideCursor("CRefMapGrid::mouseReleasePointMove"); ++ } ++ else ++ { ++ COverlayRefMapPoint * point = dynamic_cast(treeWidget->topLevelItem(idx)); ++ if(point == nullptr) ++ { ++ return; ++ } ++ treeWidget->setCurrentItem(point); ++ treeWidget->scrollToItem(point); ++ ++ QPointF pt1 = point->getPtPtx(); ++ ptFocus1 = pt1; ++ ptFocus2 = pt; ++ context->convertMap2Screen(pt1); ++ ++ QPointF pt2 = context->getCanvas()->rect().center(); ++ context->move(pt2 - pt1); ++ context->triggerCompleteUpdate(CCanvas::eRedrawAll); ++ } ++ break; ++ } ++ } ++ } ++ else ++ { ++ if(ptFocus1 != NOPOINTF) ++ { ++ ptFocus2 = pt; ++ movePoint = true; ++ CCanvas::setOverrideCursor(Qt::BlankCursor, "CRefMapGrid::mouseReleasePointMove"); ++ } ++ } ++ } ++ else if(button == Qt::RightButton) ++ { ++ if(!movePoint) ++ { ++ toolNone->click(); ++ } ++ abortStep(); ++ CCanvas::restoreOverrideCursor("CRefMapGrid::mouseReleasePointMove"); ++ } ++} ++ ++ ++bool COverlayRefMap::keyPressEventFx(QKeyEvent *e) ++{ ++ QTreeWidgetItem * item = treeWidget->currentItem(); ++ if(item == nullptr) ++ { ++ return false; ++ } ++ ++ int idx = treeWidget->indexOfTopLevelItem(item); ++ ++ switch(e->key()) ++ { ++ case Qt::Key_N: ++ { ++ ++idx; ++ idx = qMin(idx, treeWidget->topLevelItemCount() - 1); ++ break; ++ } ++ ++ case Qt::Key_B: ++ { ++ --idx; ++ idx = qMax(idx, 0); ++ break; ++ } ++ ++ default: ++ return false; ++ } ++ ++ ++ if(movePoint) ++ { ++ switch(mode) ++ { ++ case eModePointMove: ++ return false; ++ ++ case eModePointMoveAuto: ++ abortStep(); ++ CCanvas::restoreOverrideCursor("CRefMapGrid::mouseReleasePointMove"); ++ break; ++ } ++ } ++ ++ COverlayRefMapPoint * point = dynamic_cast(treeWidget->topLevelItem(idx)); ++ if(point == nullptr) ++ { ++ return false; ++ } ++ treeWidget->setCurrentItem(point); ++ treeWidget->scrollToItem(point); ++ ++ QPointF pt1 = point->getPtPtx(); ++ QPointF pt2 = context->getCanvas()->rect().center(); ++ context->convertMap2Screen(pt1); ++ context->move(pt2 - pt1); ++ ++ context->triggerCompleteUpdate(CCanvas::eRedrawAll); ++ ++ return true; ++} ++ ++QCursor COverlayRefMap::getCursorFx() ++{ ++ switch(mode) ++ { ++ case COverlayRefMap::eModePointAdd: ++ return Qt::BlankCursor; ++ ++ case COverlayRefMap::eModePointDel: ++ return QCursor(QPixmap(":/cursors/cursorPointDel.png"), 0, 0); ++ ++ case COverlayRefMap::eModePointMoveAuto: ++ case COverlayRefMap::eModePointMove: ++ return QCursor(QPixmap(":/cursors/cursorPointMove.png"), 0, 0); ++ } ++ ++ return Qt::ArrowCursor; ++} ++ ++void COverlayRefMap::updateGui() ++{ ++ bool isEmpty = treeWidget->topLevelItemCount() == 0; ++ toolRefDel->setDisabled(isEmpty); ++ toolRefMove->setDisabled(isEmpty); ++ toolRefDelAll->setDisabled(isEmpty); ++ toolRefMoveAuto->setDisabled(isEmpty); ++ toolSaveGcp->setDisabled(isEmpty); ++} ++ ++void COverlayRefMap::abortStep() ++{ ++ movePoint = false; ++ ptFocus1 = NOPOINTF; ++ ptFocus2 = NOPOINTF; ++ ++ context->triggerCompleteUpdate(CCanvas::eRedrawOverlay); ++} ++ ++void COverlayRefMap::slotSetMode(mode_e m, bool on) ++{ ++ if(on) ++ { ++ mode = m; ++ } ++} ++ ++void COverlayRefMap::slotSaveGcp() ++{ ++ SETTINGS; ++ QString path = cfg.value("Path/gcpInput", QDir::homePath()).toString(); ++ ++ QString filename = QFileDialog::getSaveFileName(0, tr("Save reference points..."), path + "/" + gcpFilename, "Ref. points (*.gcp)"); ++ if(filename.isEmpty()) ++ { ++ return; ++ } ++ cfg.setValue("Path/gcpInput", QFileInfo(filename).absolutePath()); ++ ++ gcpFilename = filename; ++ ++ QFile file(filename); ++ file.open(QIODevice::WriteOnly); ++ QTextStream out(&file); ++ out.setRealNumberPrecision(10); ++ ++ out << "#V1.0" << endl; ++ out << "#gcpproj: +proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs" << endl; ++ ++ const int N = treeWidget->topLevelItemCount(); ++ for(int n = 0; n < N; n++) ++ { ++ COverlayRefMapPoint * pt = dynamic_cast(treeWidget->topLevelItem(n)); ++ if(pt == nullptr) ++ { ++ continue; ++ } ++ const QPointF& ptx = pt->getPtPtx(); ++ const QPointF& ref = pt->getPtRef(); ++ ++ out << "-gcp " << ptx.x() << " " << ptx.y() << " " << ref.y() << " " << ref.x() << endl; ++ } ++ ++ file.close(); ++} ++ ++void COverlayRefMap::slotLoadGcp() ++{ ++ SETTINGS; ++ QString path = cfg.value("Path/gcpInput", QDir::homePath()).toString(); ++ ++ QString filename = QFileDialog::getOpenFileName(0, tr("Load reference points..."), path, "Ref. points (*.gcp)"); ++ if(filename.isEmpty()) ++ { ++ return; ++ } ++ cfg.setValue("Path/gcpInput", QFileInfo(filename).absolutePath()); ++ ++ QFile file(filename); ++ file.open(QIODevice::ReadOnly); ++ QString line = file.readLine(); ++ if(line.trimmed() == "#V1.0") ++ { ++ QRegExp re1("^-gcp\\s(-{0,1}[0-9]+)\\s(-{0,1}[0-9]+)\\s(-{0,1}[0-9\\.]+)\\s(-{0,1}[0-9\\.]+).*$"); ++ QRegExp re2("^-a_srs\\s(.*)$"); ++ QRegExp re3("^#gcpproj:\\s(.*)$"); ++ ++ qint32 cnt = 1; ++ while(1) ++ { ++ if(re1.exactMatch(line)) ++ { ++ QPointF ptPtx(re1.cap(1).toDouble(),re1.cap(2).toDouble()); ++ QPointF ptRef(re1.cap(4).toDouble(),re1.cap(3).toDouble()); ++ new COverlayRefMapPoint(cnt++, ptRef, ptPtx, treeWidget); ++ } ++ ++ if (file.atEnd()) ++ { ++ break; ++ } ++ line = file.readLine(); ++ } ++ } ++ ++ updateGui(); ++ ++ emit sigChanged(); ++} ++ ++void COverlayRefMap::slotResetRef() ++{ ++ int res = QMessageBox::question(this, tr("Delete all reference points..."), tr("Are you sure to delete all reference points in the list?"), QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes); ++ if(res != QMessageBox::Yes) ++ { ++ return; ++ } ++ treeWidget->clear(); ++ updateGui(); ++ ++ emit sigChanged(); ++} ++ ++void COverlayRefMap::slotProjWizard() ++{ ++ CProjWizard dlg(*lineProjection, this); ++ dlg.exec(); ++ lineProjection->setCursorPosition(0); ++ ++ emit sigChanged(); ++} ++ ++void COverlayRefMap::slotGridTool() ++{ ++ CMainWindow::self().startGridTool(item); ++} ++ ++void COverlayRefMap::slotSelectionChanged() ++{ ++ context->triggerCompleteUpdate(CCanvas::eRedrawOverlay); ++} ++ ++void COverlayRefMap::slotDelRefPoints() ++{ ++ const QListitems = treeWidget->selectedItems(); ++ if(items.count() > 1) ++ { ++ int res = QMessageBox::question(this, tr("Delete..."), tr("Delete all selected reference points?"), QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes); ++ if(res != QMessageBox::Yes) ++ { ++ return; ++ } ++ } ++ ++ qDeleteAll(items); ++ ++ emit sigChanged(); ++} ++ ++bool COverlayRefMap::isOk() const ++{ ++ bool ok = true; ++ ok &= (treeWidget->topLevelItemCount() > 2); ++ ok &= CProjWizard::validProjStr(lineProjection->text()); ++ return ok; ++} +diff --git a/src/qmaptool/overlay/COverlayRefMap.h b/src/qmaptool/overlay/COverlayRefMap.h +new file mode 100644 +index 00000000..03391000 +--- /dev/null ++++ b/src/qmaptool/overlay/COverlayRefMap.h +@@ -0,0 +1,103 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef COVERLAYREFMAP_H ++#define COVERLAYREFMAP_H ++ ++#include "overlay/IOverlay.h" ++#include "ui_IOverlayRefMap.h" ++#include "units/IUnit.h" ++ ++class QStackedWidget; ++class IDrawContext; ++class QSettings; ++class CItemRefMap; ++class COverlayRefMapPoint; ++ ++class COverlayRefMap : public IOverlay, private Ui::IOverlayRefMap ++{ ++ Q_OBJECT ++public: ++ COverlayRefMap(CItemRefMap *item, QStackedWidget * stackedWidget); ++ virtual ~COverlayRefMap() = default; ++ ++ void saveSettings(QSettings& cfg); ++ void loadSettings(QSettings& cfg); ++ ++ void addRefPoints(QList& points); ++ QString getMapProjection() const; ++ const QList getRefPoints() const; ++ ++ bool drawFx(QPainter& p, CCanvas::redraw_e needsRedraw); ++ void mouseMoveEventFx(QMouseEvent *e); ++ void mouseReleaseEventFx(QMouseEvent *e); ++ bool keyPressEventFx(QKeyEvent *e); ++ QCursor getCursorFx(); ++ ++ void abortStep(); ++ ++ enum mode_e ++ { ++ eModeNone ++ ,eModePointMove ++ ,eModePointAdd ++ ,eModePointDel ++ ,eModePointMoveAuto ++ }; ++ ++ bool isOk() const; ++ ++private slots: ++ void slotSetMode(mode_e m, bool on); ++ void slotSaveGcp(); ++ void slotLoadGcp(); ++ void slotResetRef(); ++ void slotProjWizard(); ++ void slotGridTool(); ++ void slotSelectionChanged(); ++ void slotDelRefPoints(); ++ void slotSortRefPoints(); ++ ++ ++private: ++ void updateGui(); ++ QPointF isCloseTo(QPointF pt); ++ ++ void mouseMovePointAdd(const QPointF &pt); ++ void mouseMovePointDel(const QPointF &pt); ++ void mouseMovePointMove(const QPointF &pt); ++ ++ void mouseReleasePointAdd(const QPointF &pt, Qt::MouseButton button); ++ void mouseReleasePointDel(const QPointF &pt, Qt::MouseButton button); ++ void mouseReleasePointMove(const QPointF &pt, Qt::MouseButton button); ++ ++ IDrawContext* context; ++ CItemRefMap * item; ++ ++ mode_e mode = eModeNone; ++ ++ QPointF ptFocus1 = NOPOINTF; ++ QPointF ptFocus2 = NOPOINTF; ++ bool movePoint = false; ++ ++ QString gcpFilename; ++}; ++ ++#endif //COVERLAYREFMAP_H ++ ++ +diff --git a/src/qmaptool/overlay/IOverlay.cpp b/src/qmaptool/overlay/IOverlay.cpp +new file mode 100644 +index 00000000..148d1c10 +--- /dev/null ++++ b/src/qmaptool/overlay/IOverlay.cpp +@@ -0,0 +1,36 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "overlay/IOverlay.h" ++ ++#include ++ ++IOverlay::IOverlay(QStackedWidget *parent) ++ : QWidget(parent) ++ , stackedWidget(parent) ++{ ++ stackedWidget->addWidget(this); ++} ++ ++ ++void IOverlay::toFront() ++{ ++ stackedWidget->setCurrentWidget(this); ++} ++ ++ +diff --git a/src/qmaptool/overlay/IOverlay.h b/src/qmaptool/overlay/IOverlay.h +new file mode 100644 +index 00000000..d7e968ec +--- /dev/null ++++ b/src/qmaptool/overlay/IOverlay.h +@@ -0,0 +1,43 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef IOVERLAY_H ++#define IOVERLAY_H ++ ++#include ++ ++class QStackedWidget; ++ ++class IOverlay : public QWidget ++{ ++ Q_OBJECT ++public: ++ IOverlay(QStackedWidget * parent); ++ virtual ~IOverlay() = default; ++ ++ void toFront(); ++ ++signals: ++ void sigChanged(); ++ ++protected: ++ QStackedWidget * stackedWidget; ++}; ++ ++#endif //IOVERLAY_H ++ +diff --git a/src/qmaptool/overlay/IOverlayCutMap.ui b/src/qmaptool/overlay/IOverlayCutMap.ui +new file mode 100644 +index 00000000..e7a69766 +--- /dev/null ++++ b/src/qmaptool/overlay/IOverlayCutMap.ui +@@ -0,0 +1,202 @@ ++ ++ ++ IOverlayCutMap ++ ++ ++ ++ 0 ++ 0 ++ 254 ++ 25 ++ ++ ++ ++ Form ++ ++ ++ ++ 3 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ ++ ++ Just move the map and zoom. ++ ++ ++ ++ ++ ++ ++ :/icons/32x32/MoveArrow.png:/icons/32x32/MoveArrow.png ++ ++ ++ true ++ ++ ++ true ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ Add point to mask. ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/PointAdd.png:/icons/32x32/PointAdd.png ++ ++ ++ true ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ false ++ ++ ++ Move point of mask. ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/PointMove.png:/icons/32x32/PointMove.png ++ ++ ++ true ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ false ++ ++ ++ Remove point from mask. ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/PointDel.png:/icons/32x32/PointDel.png ++ ++ ++ true ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ Qt::Vertical ++ ++ ++ ++ ++ ++ ++ false ++ ++ ++ Remove complete cut mask. ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/PointDelAll.png:/icons/32x32/PointDelAll.png ++ ++ ++ ++ ++ ++ ++ Qt::Vertical ++ ++ ++ ++ ++ ++ ++ Load cut mask from shape file. ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/LoadShape.png:/icons/32x32/LoadShape.png ++ ++ ++ ++ ++ ++ ++ false ++ ++ ++ Save cut mask to shape file. ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/SaveShape.png:/icons/32x32/SaveShape.png ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ 40 ++ 20 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/src/qmaptool/overlay/IOverlayGridTool.ui b/src/qmaptool/overlay/IOverlayGridTool.ui +new file mode 100644 +index 00000000..7e8c1ab3 +--- /dev/null ++++ b/src/qmaptool/overlay/IOverlayGridTool.ui +@@ -0,0 +1,184 @@ ++ ++ ++ IOverlayGridTool ++ ++ ++ ++ 0 ++ 0 ++ 400 ++ 462 ++ ++ ++ ++ Form ++ ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ true ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ Qt::Vertical ++ ++ ++ ++ 20 ++ 40 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ Qt::Vertical ++ ++ ++ ++ 20 ++ 40 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ false ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ Qt::Vertical ++ ++ ++ ++ 20 ++ 40 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ false ++ ++ ++ ++ ++ ++ ++ false ++ ++ ++ do not translate ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ CGridPlacer ++ QWidget ++
overlay/gridtool/CGridPlacer.h
++ 1 ++
++ ++ CGridSelArea ++ QWidget ++
overlay/gridtool/CGridSelArea.h
++ 1 ++
++ ++ CGridSetRef ++ QWidget ++
overlay/gridtool/CGridSetRef.h
++ 1 ++
++
++ ++ radioSetRef ++ radioGridPlacer ++ radioSelectArea ++ ++ ++ ++
+diff --git a/src/qmaptool/overlay/IOverlayRefMap.ui b/src/qmaptool/overlay/IOverlayRefMap.ui +new file mode 100644 +index 00000000..9001fe66 +--- /dev/null ++++ b/src/qmaptool/overlay/IOverlayRefMap.ui +@@ -0,0 +1,351 @@ ++ ++ ++ IOverlayRefMap ++ ++ ++ ++ 0 ++ 0 ++ 400 ++ 376 ++ ++ ++ ++ Form ++ ++ ++ ++ 3 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 3 ++ ++ ++ ++ ++ 3 ++ ++ ++ ++ ++ Just move the map and zoom. ++ ++ ++ ++ ++ ++ ++ :/icons/32x32/MoveArrow.png:/icons/32x32/MoveArrow.png ++ ++ ++ true ++ ++ ++ true ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ Add reference point. ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/RefAdd.png:/icons/32x32/RefAdd.png ++ ++ ++ true ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ false ++ ++ ++ Move reference point. ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/RefMove.png:/icons/32x32/RefMove.png ++ ++ ++ true ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ false ++ ++ ++ Remove single reference point. ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/RefDel.png:/icons/32x32/RefDel.png ++ ++ ++ true ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ false ++ ++ ++ Move reference points with auto mode. This will pickup the next point after you moved a reference point. ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/RefMoveAuto.png:/icons/32x32/RefMoveAuto.png ++ ++ ++ true ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ Qt::Vertical ++ ++ ++ ++ ++ ++ ++ false ++ ++ ++ Remove all reference points. ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/RefDelAll.png:/icons/32x32/RefDelAll.png ++ ++ ++ ++ ++ ++ ++ Switch to the Grid Tool. ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/GridTool.png:/icons/32x32/GridTool.png ++ ++ ++ ++ ++ ++ ++ Qt::Vertical ++ ++ ++ ++ ++ ++ ++ Load reference points from GCP file. ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/LoadGcp.png:/icons/32x32/LoadGcp.png ++ ++ ++ ++ ++ ++ ++ false ++ ++ ++ Save reference points into GCP file. ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/SaveGcp.png:/icons/32x32/SaveGcp.png ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ 40 ++ 20 ++ ++ ++ ++ ++ ++ ++ ++ Sort list of reference points. ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/Sort.png:/icons/32x32/Sort.png ++ ++ ++ ++ ++ ++ ++ ++ ++ Qt::ActionsContextMenu ++ ++ ++ QAbstractItemView::ExtendedSelection ++ ++ ++ QAbstractItemView::SelectRows ++ ++ ++ false ++ ++ ++ false ++ ++ ++ false ++ ++ ++ ++ # ++ ++ ++ ++ ++ (x, y)[pixel] ++ ++ ++ ++ ++ (lat, lon)[°] ++ ++ ++ ++ ++ ++ ++ ++ TextLabel ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ Final Map Projection: ++ ++ ++ ++ ++ ++ ++ 3 ++ ++ ++ ++ ++ Enter a valid projection string. Valid strings are "+proj..." or "+init=epsg:...". ++ ++ ++ ++ ++ ++ ++ Start projection wizard. ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/GridWizard.png:/icons/32x32/GridWizard.png ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ :/icons/32x32/DeleteMultiple.png:/icons/32x32/DeleteMultiple.png ++ ++ ++ Delete ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/src/qmaptool/overlay/gridtool/CGridPlacer.cpp b/src/qmaptool/overlay/gridtool/CGridPlacer.cpp +new file mode 100644 +index 00000000..62b211c3 +--- /dev/null ++++ b/src/qmaptool/overlay/gridtool/CGridPlacer.cpp +@@ -0,0 +1,274 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "canvas/IDrawContext.h" ++#include "items/CItemRefMap.h" ++#include "overlay/gridtool/CGridPlacer.h" ++#include "overlay/gridtool/CGridPoint.h" ++ ++#include ++#include ++using std::bind; ++ ++ ++CGridPlacer::CGridPlacer(QWidget *parent) ++ : QWidget(parent) ++{ ++ setupUi(this); ++ ++ labelHelp->setText(tr("Select one of the corners and place the marker at " ++ "the corresponding grid crossing on the map. All " ++ "4 corners have to be placed.")); ++ ++ QButtonGroup * group = new QButtonGroup(this); ++ group->addButton(radioPoint1); ++ group->addButton(radioPoint2); ++ group->addButton(radioPoint3); ++ group->addButton(radioPoint4); ++ ++ connect(radioPoint1, &QToolButton::toggled, this, bind(&CGridPlacer::slotSetPoint, this, 0, std::placeholders::_1)); ++ connect(radioPoint2, &QToolButton::toggled, this, bind(&CGridPlacer::slotSetPoint, this, 1, std::placeholders::_1)); ++ connect(radioPoint3, &QToolButton::toggled, this, bind(&CGridPlacer::slotSetPoint, this, 2, std::placeholders::_1)); ++ connect(radioPoint4, &QToolButton::toggled, this, bind(&CGridPlacer::slotSetPoint, this, 3, std::placeholders::_1)); ++ connect(pushReset, &QPushButton::clicked, this, &CGridPlacer::slotReset); ++ connect(pushSetArea, &QPushButton::clicked, this, &CGridPlacer::slotSetArea); ++} ++ ++void CGridPlacer::registerItem(CItemRefMap * item) ++{ ++ this->item = item; ++ ++ if(item != nullptr) ++ { ++ points = QVector(4); ++ ++ for(CGridPoint& point : points) ++ { ++ point.registerItem(item); ++ } ++ ++ radioPoint1->setChecked(true); ++ } ++} ++ ++void CGridPlacer::saveSettings(QSettings& cfg) ++{ ++ cfg.beginGroup("Points"); ++ for(int i = 0; i < points.size(); i++) ++ { ++ const QPointF& pt = points[i].getPoint(); ++ if(pt != NOPOINTF) ++ { ++ cfg.setValue(QString::number(i), pt); ++ } ++ } ++ cfg.endGroup(); ++} ++ ++void CGridPlacer::loadSettings(QSettings& cfg) ++{ ++ cfg.beginGroup("Points"); ++ for(int i = 0; i < points.size(); i++) ++ { ++ QPointF pt = cfg.value(QString::number(i), NOPOINTF).toPointF(); ++ points[i].setPoint(pt); ++ } ++ cfg.endGroup(); ++ updateStatus(); ++} ++ ++bool CGridPlacer::drawFx(QPainter& p, CCanvas::redraw_e needsRedraw) ++{ ++ for(CGridPoint& point : points) ++ { ++ point.drawFx(p, needsRedraw); ++ } ++ ++ return true; ++} ++ ++void CGridPlacer::mouseMoveEventFx(QMouseEvent *e) ++{ ++ points[idx].mouseMoveEventFx(e); ++} ++ ++void CGridPlacer::mouseReleaseEventFx(QMouseEvent *e) ++{ ++ points[idx].mouseReleaseEventFx(e); ++ updateStatus(); ++} ++ ++void CGridPlacer::leaveEventFx(QEvent *e) ++{ ++ points[idx].leaveEventFx(e); ++} ++ ++QCursor CGridPlacer::getCursorFx() ++{ ++ return points[idx].getCursorFx(); ++} ++ ++void CGridPlacer::slotSetPoint(qint32 i, bool on) ++{ ++ if(on) ++ { ++ idx = i; ++ } ++} ++ ++void CGridPlacer::slotReset() ++{ ++ for(CGridPoint& point : points) ++ { ++ point.setPoint(NOPOINTF); ++ } ++ ++ updateStatus(); ++ ++ item->getDrawContext()->triggerCompleteUpdate(CCanvas::eRedrawOverlay); ++} ++ ++void CGridPlacer::updateStatus() ++{ ++ /// @todo optimize this ++ ++ const QPointF& pt1 = points[0].getPoint(); ++ const QPointF& pt2 = points[1].getPoint(); ++ const QPointF& pt3 = points[2].getPoint(); ++ const QPointF& pt4 = points[3].getPoint(); ++ ++ statusIsOk = true; ++ ++ if(pt1 == NOPOINTF) ++ { ++ statusIsOk = false; ++ labelStatusPoint1->setText(tr("Point 1 - not set")); ++ } ++ else ++ { ++ labelStatusPoint1->setText("" + tr("Point 1 - ok") + ""); ++ ++ if((pt2 != NOPOINTF) && (pt2.x() < pt1.x())) ++ { ++ statusIsOk = false; ++ labelStatusPoint1->setText("" + tr("Point 1 - bad") + ""); ++ } ++ if((pt4 != NOPOINTF) && (pt4.y() < pt1.y())) ++ { ++ statusIsOk = false; ++ labelStatusPoint1->setText("" + tr("Point 1 - bad") + ""); ++ } ++ } ++ ++ if(pt2 == NOPOINTF) ++ { ++ statusIsOk = false; ++ labelStatusPoint2->setText(tr("Point 2 - not set")); ++ } ++ else ++ { ++ labelStatusPoint2->setText("" + tr("Point 2 - ok") + ""); ++ ++ if((pt1 != NOPOINTF) && (pt1.x() > pt2.x())) ++ { ++ statusIsOk = false; ++ labelStatusPoint2->setText("" + tr("Point 2 - bad") + ""); ++ } ++ if((pt3 != NOPOINTF) && (pt3.y() < pt2.y())) ++ { ++ statusIsOk = false; ++ labelStatusPoint2->setText("" + tr("Point 2 - bad") + ""); ++ } ++ } ++ ++ ++ if(pt3 == NOPOINTF) ++ { ++ statusIsOk = false; ++ labelStatusPoint3->setText(tr("Point 3 - not set")); ++ } ++ else ++ { ++ labelStatusPoint3->setText("" + tr("Point 3 - ok") + ""); ++ ++ if((pt4 != NOPOINTF) && (pt4.x() > pt3.x())) ++ { ++ statusIsOk = false; ++ labelStatusPoint3->setText("" + tr("Point 3 - bad") + ""); ++ } ++ if((pt2 != NOPOINTF) && (pt2.y() > pt3.y())) ++ { ++ statusIsOk = false; ++ labelStatusPoint3->setText("" + tr("Point 3 - bad") + ""); ++ } ++ } ++ ++ ++ if(pt4 == NOPOINTF) ++ { ++ statusIsOk = false; ++ labelStatusPoint4->setText(tr("Point 4 - not set")); ++ } ++ else ++ { ++ labelStatusPoint4->setText("" + tr("Point 4 - ok") + ""); ++ ++ if((pt3 != NOPOINTF) && (pt3.x() < pt4.x())) ++ { ++ statusIsOk = false; ++ labelStatusPoint4->setText("" + tr("Point 4 - bad") + ""); ++ } ++ if((pt1 != NOPOINTF) && (pt1.y() > pt4.y())) ++ { ++ statusIsOk = false; ++ labelStatusPoint4->setText("" + tr("Point 4 - bad") + ""); ++ } ++ } ++ ++ pushSetArea->setEnabled(statusIsOk); ++ ++ emit sigChanged(); ++} ++ ++ ++void CGridPlacer::slotSetArea() const ++{ ++ qreal bottom = -NOFLOAT; ++ qreal top = NOFLOAT; ++ qreal left = NOFLOAT; ++ qreal right = -NOFLOAT; ++ ++ for(const CGridPoint& point : points) ++ { ++ const QPointF& pt = point.getPoint(); ++ ++ top = qMin(pt.y(), top); ++ bottom = qMax(pt.y(), bottom); ++ left = qMin(pt.x(), left); ++ right = qMax(pt.x(), right); ++ } ++ ++ QRectF r(0,0,1,1); ++ r.setLeft(left); ++ r.setRight(right); ++ r.setTop(top); ++ r.setBottom(bottom); ++ ++ ++ emit sigSetArea(r); ++} +diff --git a/src/qmaptool/overlay/gridtool/CGridPlacer.h b/src/qmaptool/overlay/gridtool/CGridPlacer.h +new file mode 100644 +index 00000000..8d321041 +--- /dev/null ++++ b/src/qmaptool/overlay/gridtool/CGridPlacer.h +@@ -0,0 +1,85 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CGRIDPLACER_H ++#define CGRIDPLACER_H ++ ++#include "canvas/CCanvas.h" ++#include "overlay/gridtool/CGridPoint.h" ++ ++#include "ui_IGridPlacer.h" ++ ++class CItemRefMap; ++class QSettings; ++ ++class CGridPlacer : public QWidget, private Ui::IGridPlacer ++{ ++ Q_OBJECT ++public: ++ CGridPlacer(QWidget * parent); ++ virtual ~CGridPlacer() = default; ++ ++ void registerItem(CItemRefMap * item); ++ ++ void saveSettings(QSettings& cfg); ++ void loadSettings(QSettings& cfg); ++ ++ bool drawFx(QPainter& p, CCanvas::redraw_e needsRedraw); ++ void mouseMoveEventFx(QMouseEvent *e); ++ void mouseReleaseEventFx(QMouseEvent *e); ++ void leaveEventFx(QEvent *e); ++ QCursor getCursorFx(); ++ ++ bool isOk() const ++ { ++ return statusIsOk; ++ } ++ ++ const QPointF& getPoint(int idx) const ++ { ++ if(idx < points.count()) ++ { ++ return points[idx].getPoint(); ++ } ++ return NOPOINTF; ++ } ++ ++signals: ++ void sigChanged(); ++ void sigSetArea(const QRectF& area) const; ++ ++public slots: ++ void slotReset(); ++ ++private slots: ++ void slotSetPoint(qint32 i, bool on); ++ void slotSetArea() const; ++ ++private: ++ void updateStatus(); ++ CItemRefMap * item = nullptr; ++ ++ qint32 idx = 0; ++ ++ QVector points; ++ ++ bool statusIsOk = false; ++}; ++ ++#endif //CGRIDPLACER_H ++ +diff --git a/src/qmaptool/overlay/gridtool/CGridPoint.cpp b/src/qmaptool/overlay/gridtool/CGridPoint.cpp +new file mode 100644 +index 00000000..b1a1cf6e +--- /dev/null ++++ b/src/qmaptool/overlay/gridtool/CGridPoint.cpp +@@ -0,0 +1,184 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "canvas/IDrawContext.h" ++#include "helpers/CDraw.h" ++#include "items/CItemRefMap.h" ++#include "overlay/gridtool/CGridPoint.h" ++ ++#include ++ ++CGridPoint::CGridPoint() ++{ ++} ++ ++void CGridPoint::registerItem(CItemRefMap * item) ++{ ++ this->item = item; ++ ++ if(item != nullptr) ++ { ++ context = item->getDrawContext(); ++ if(context == nullptr) ++ { ++ this->item = nullptr; ++ } ++ } ++ else ++ { ++ context = nullptr; ++ } ++} ++ ++bool CGridPoint::drawFx(QPainter& p, CCanvas::redraw_e needsRedraw) ++{ ++ if(ptFocus1 != NOPOINTF) ++ { ++ QPointF pt = ptFocus1; ++ context->convertMap2Screen(pt); ++ CDraw::drawCrossHairDot(p, pt); ++ } ++ ++ if(ptPoint != NOPOINTF) ++ { ++ QPointF pt = ptPoint; ++ context->convertMap2Screen(pt); ++ ++ QRectF dot1(0,0,7,7); ++ dot1.moveCenter(pt); ++ ++ if(state == eStateHighlight) ++ { ++ p.setPen(QPen(QColor("#ffaa00"), 2)); ++ p.setBrush(QColor("#ffaa00")); ++ } ++ else ++ { ++ p.setPen(QPen(Qt::white, 1)); ++ p.setBrush(QColor("#ffaa00")); ++ } ++ ++ p.drawRect(dot1); ++ } ++ ++ return true; ++} ++ ++void CGridPoint::mouseMoveEventFx(QMouseEvent *e) ++{ ++ QPointF pt = e->pos(); ++ ++ ++ switch(state) ++ { ++ case eStateMove: ++ case eStateNotSet: ++ context->convertScreen2Map(pt); ++ ptFocus1 = pt; ++ break; ++ ++ case eStateSet: ++ { ++ QPointF point = ptPoint; ++ context->convertMap2Screen(point); ++ if((point - pt).manhattanLength() < 30) ++ { ++ state = eStateHighlight; ++ } ++ break; ++ } ++ ++ case eStateHighlight: ++ { ++ QPointF point = ptPoint; ++ context->convertMap2Screen(point); ++ if((point - pt).manhattanLength() >= 30) ++ { ++ state = eStateSet; ++ } ++ break; ++ } ++ } ++ ++ context->triggerCompleteUpdate(CCanvas::eRedrawOverlay); ++} ++ ++void CGridPoint::mouseReleaseEventFx(QMouseEvent *e) ++{ ++ switch(state) ++ { ++ case eStateMove: ++ case eStateNotSet: ++ ptPoint = ptFocus1; ++ ptFocus1 = NOPOINTF; ++ state = eStateSet; ++ CCanvas::restoreOverrideCursor("CGridPoint::mouseReleaseEventFx"); ++ break; ++ ++ case eStateSet: ++ break; ++ ++ case eStateHighlight: ++ ptFocus1 = ptPoint; ++ ptPoint = NOPOINTF; ++ state = eStateMove; ++ CCanvas::setOverrideCursor(Qt::BlankCursor, "CGridPoint::mouseReleaseEventFx"); ++ break; ++ } ++ ++ context->triggerCompleteUpdate(CCanvas::eRedrawOverlay); ++} ++ ++void CGridPoint::leaveEventFx(QEvent *e) ++{ ++ ptFocus1 = NOPOINTF; ++ ++ switch(state) ++ { ++ case eStateNotSet: ++ case eStateSet: ++ break; ++ ++ case eStateHighlight: ++ case eStateMove: ++ state = eStateSet; ++ break; ++ } ++ ++ context->triggerCompleteUpdate(CCanvas::eRedrawOverlay); ++} ++ ++QCursor CGridPoint::getCursorFx() ++{ ++ switch(state) ++ { ++ case eStateNotSet: ++ return Qt::BlankCursor; ++ ++ case eStateSet: ++ return Qt::ArrowCursor; ++ ++ case eStateHighlight: ++ return Qt::ArrowCursor; ++ ++ case eStateMove: ++ return Qt::BlankCursor; ++ } ++ ++ return Qt::ArrowCursor; ++} +diff --git a/src/qmaptool/overlay/gridtool/CGridPoint.h b/src/qmaptool/overlay/gridtool/CGridPoint.h +new file mode 100644 +index 00000000..5db2d868 +--- /dev/null ++++ b/src/qmaptool/overlay/gridtool/CGridPoint.h +@@ -0,0 +1,70 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CGRIDPOINT_H ++#define CGRIDPOINT_H ++ ++#include "canvas/CCanvas.h" ++#include "units/IUnit.h" ++ ++class CItemRefMap; ++class IDrawContext; ++ ++class CGridPoint ++{ ++public: ++ CGridPoint(); ++ virtual ~CGridPoint() = default; ++ ++ void registerItem(CItemRefMap * item); ++ ++ bool drawFx(QPainter& p, CCanvas::redraw_e needsRedraw); ++ void mouseMoveEventFx(QMouseEvent *e); ++ void mouseReleaseEventFx(QMouseEvent *e); ++ void leaveEventFx(QEvent *e); ++ QCursor getCursorFx(); ++ ++ const QPointF& getPoint() const ++ { ++ return ptPoint; ++ } ++ ++ void setPoint(const QPointF& pt) ++ { ++ ptPoint = pt; ++ state = pt == NOPOINTF ? eStateNotSet : eStateSet; ++ } ++ ++private: ++ enum state_e ++ { ++ eStateNotSet ++ ,eStateSet ++ ,eStateHighlight ++ ,eStateMove ++ }; ++ ++ state_e state = eStateNotSet; ++ CItemRefMap * item = nullptr; ++ const IDrawContext * context = nullptr; ++ QPointF ptPoint = NOPOINTF; ++ QPointF ptFocus1 = NOPOINTF; ++}; ++ ++#endif //CGRIDPOINT_H ++ +diff --git a/src/qmaptool/overlay/gridtool/CGridSelArea.cpp b/src/qmaptool/overlay/gridtool/CGridSelArea.cpp +new file mode 100644 +index 00000000..d929633d +--- /dev/null ++++ b/src/qmaptool/overlay/gridtool/CGridSelArea.cpp +@@ -0,0 +1,240 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "canvas/IDrawContext.h" ++#include "helpers/CDraw.h" ++#include "items/CItemRefMap.h" ++#include "overlay/gridtool/CGridSelArea.h" ++ ++#include ++ ++CGridSelArea::CGridSelArea(QWidget *parent) ++ : QWidget(parent) ++{ ++ setupUi(this); ++ labelHelp->setText(tr("Select the area to be covered by the calculated reference points. Simply grab " ++ "the corners of the selection rectangle with a left click and place them where " ++ "you want with a second click.")); ++} ++ ++ ++void CGridSelArea::registerItem(CItemRefMap * item) ++{ ++ this->item = item; ++ ++ if(item != nullptr) ++ { ++ context = item->getDrawContext(); ++ if(context == nullptr) ++ { ++ this->item = nullptr; ++ } ++ } ++ else ++ { ++ context = nullptr; ++ } ++} ++ ++void CGridSelArea::saveSettings(QSettings& cfg) ++{ ++ cfg.setValue("area", area); ++} ++ ++void CGridSelArea::loadSettings(QSettings& cfg) ++{ ++ area = cfg.value("area", QRectF()).toRectF(); ++ emit sigChanged(); ++} ++ ++bool CGridSelArea::drawFx(QPainter& p, CCanvas::redraw_e needsRedraw) ++{ ++ if(area.isEmpty()) ++ { ++ return false; ++ } ++ ++ QRectF rect = area; ++ context->convertMap2Screen(rect); ++ ++ rectTopLeft.moveTopLeft(rect.topLeft()); ++ rectTopRight.moveTopRight(rect.topRight()); ++ rectBottomLeft.moveBottomLeft(rect.bottomLeft()); ++ rectBottomRight.moveBottomRight(rect.bottomRight()); ++ ++ CDraw::drawRectangle(p, rectTopLeft, Qt::black, Qt::lightGray); ++ CDraw::drawRectangle(p, rectTopRight, Qt::black, Qt::lightGray); ++ CDraw::drawRectangle(p, rectBottomLeft, Qt::black, Qt::lightGray); ++ CDraw::drawRectangle(p, rectBottomRight, Qt::black, Qt::lightGray); ++ ++ p.setBrush(Qt::red); ++ switch(corner) ++ { ++ case eCornerTopLeft: ++ CDraw::drawRectangle(p, rectTopLeft, Qt::black, Qt::red); ++ break; ++ ++ case eCornerTopRight: ++ CDraw::drawRectangle(p, rectTopRight, Qt::black, Qt::red); ++ break; ++ ++ case eCornerBottomLeft: ++ CDraw::drawRectangle(p, rectBottomLeft, Qt::black, Qt::red); ++ break; ++ ++ case eCornerBottomRight: ++ CDraw::drawRectangle(p, rectBottomRight, Qt::black, Qt::red); ++ break; ++ } ++ ++ CDraw::drawRectangle(p, rect, QPen(Qt::black), Qt::NoBrush); ++ ++ return true; ++} ++ ++void CGridSelArea::mouseMoveEventFx(QMouseEvent *e) ++{ ++ switch(state) ++ { ++ case eStateIdle: ++ { ++ corner_e _corner = corner; ++ QPoint pos = e->pos(); ++ if(rectTopLeft.contains(pos)) ++ { ++ offset = pos - rectTopLeft.topLeft(); ++ corner = eCornerTopLeft; ++ } ++ else if(rectTopRight.contains(pos)) ++ { ++ offset = pos - rectTopRight.topRight(); ++ corner = eCornerTopRight; ++ } ++ else if(rectBottomLeft.contains(pos)) ++ { ++ offset = pos - rectBottomLeft.bottomLeft(); ++ corner = eCornerBottomLeft; ++ } ++ else if(rectBottomRight.contains(pos)) ++ { ++ offset = pos - rectBottomRight.bottomRight(); ++ corner = eCornerBottomRight; ++ } ++ else ++ { ++ corner = eCornerNone; ++ } ++ ++ if(corner != _corner) ++ { ++ context->triggerCompleteUpdate(CCanvas::eRedrawOverlay); ++ } ++ ++ break; ++ } ++ ++ case eStateMove: ++ { ++ QPointF pos = e->pos() - offset; ++ context->convertScreen2Map(pos); ++ ++ switch(corner) ++ { ++ case eCornerTopLeft: ++ area.setTopLeft(pos); ++ break; ++ ++ case eCornerTopRight: ++ area.setTopRight(pos); ++ break; ++ ++ case eCornerBottomLeft: ++ area.setBottomLeft(pos); ++ break; ++ ++ case eCornerBottomRight: ++ area.setBottomRight(pos); ++ break; ++ } ++ ++ emit sigChanged(); ++ context->triggerCompleteUpdate(CCanvas::eRedrawOverlay); ++ break; ++ } ++ } ++} ++ ++void CGridSelArea::mouseReleaseEventFx(QMouseEvent *e) ++{ ++ if(e->button() == Qt::LeftButton) ++ { ++ switch(state) ++ { ++ case eStateIdle: ++ { ++ if(corner != eCornerNone) ++ { ++ areaSave = area; ++ state = eStateMove; ++ } ++ break; ++ } ++ ++ case eStateMove: ++ { ++ corner = eCornerNone; ++ state = eStateIdle; ++ break; ++ } ++ } ++ } ++ else ++ { ++ area = areaSave; ++ state = eStateIdle; ++ corner = eCornerNone; ++ } ++ context->triggerCompleteUpdate(CCanvas::eRedrawOverlay); ++ emit sigChanged(); ++} ++ ++void CGridSelArea::leaveEventFx(QEvent *e) ++{ ++} ++ ++QCursor CGridSelArea::getCursorFx() ++{ ++ return Qt::ArrowCursor; ++} ++ ++ ++void CGridSelArea::slotSetArea(const QRectF& rect) ++{ ++ area = rect; ++ context->triggerCompleteUpdate(CCanvas::eRedrawOverlay); ++ emit sigChanged(); ++} ++ ++void CGridSelArea::slotReset() ++{ ++ area = QRectF(); ++ state = eStateIdle; ++ corner = eCornerNone; ++ context->triggerCompleteUpdate(CCanvas::eRedrawOverlay); ++ emit sigChanged(); ++} +diff --git a/src/qmaptool/overlay/gridtool/CGridSelArea.h b/src/qmaptool/overlay/gridtool/CGridSelArea.h +new file mode 100644 +index 00000000..1505c106 +--- /dev/null ++++ b/src/qmaptool/overlay/gridtool/CGridSelArea.h +@@ -0,0 +1,97 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CGRIDSELAREA_H ++#define CGRIDSELAREA_H ++ ++#include "canvas/CCanvas.h" ++#include "ui_IGridSelArea.h" ++ ++class CItemRefMap; ++class QSettings; ++class IDrawContext; ++ ++ ++class CGridSelArea : public QWidget, private Ui::IGridSelArea ++{ ++ Q_OBJECT ++public: ++ CGridSelArea(QWidget * parent); ++ virtual ~CGridSelArea() = default; ++ ++ void registerItem(CItemRefMap * item); ++ ++ void saveSettings(QSettings& cfg); ++ void loadSettings(QSettings& cfg); ++ ++ bool drawFx(QPainter& p, CCanvas::redraw_e needsRedraw); ++ void mouseMoveEventFx(QMouseEvent *e); ++ void mouseReleaseEventFx(QMouseEvent *e); ++ void leaveEventFx(QEvent *e); ++ QCursor getCursorFx(); ++ ++ const QRectF& getArea() const ++ { ++ return area; ++ } ++ ++public slots: ++ void slotSetArea(const QRectF& rect); ++ void slotReset(); ++ ++ ++signals: ++ void sigChanged(); ++ ++private: ++ CItemRefMap * item = nullptr; ++ const IDrawContext * context = nullptr; ++ ++ QRectF area; ++ QRectF areaSave; ++ QPointF offset; ++ ++ QRectF rectTopLeft {0, 0, 20, 20}; ++ QRectF rectTopRight {0, 0, 20, 20}; ++ QRectF rectBottomLeft {0, 0, 20, 20}; ++ QRectF rectBottomRight {0, 0, 20, 20}; ++ ++ enum state_e ++ { ++ eStateIdle ++ ,eStateMove ++ }; ++ ++ state_e state = eStateIdle; ++ ++ enum corner_e ++ { ++ eCornerNone ++ , eCornerTopLeft ++ , eCornerTopRight ++ , eCornerBottomLeft ++ , eCornerBottomRight ++ , eCornerPrint ++ , eCornerImage ++ }; ++ ++ corner_e corner = eCornerNone; ++}; ++ ++#endif //CGRIDSELAREA_H ++ +diff --git a/src/qmaptool/overlay/gridtool/CGridSetRef.cpp b/src/qmaptool/overlay/gridtool/CGridSetRef.cpp +new file mode 100644 +index 00000000..c027cf15 +--- /dev/null ++++ b/src/qmaptool/overlay/gridtool/CGridSetRef.cpp +@@ -0,0 +1,105 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "CMainWindow.h" ++#include "overlay/gridtool/CGridSetRef.h" ++#include "overlay/refmap/CProjWizard.h" ++ ++#include ++ ++CGridSetRef::CGridSetRef(QWidget *parent) ++ : QWidget(parent) ++{ ++ setupUi(this); ++ ++ connect(toolGridProj, &QToolButton::clicked, this, &CGridSetRef::slotSetupGridProj); ++ connect(lineEasting, &QLineEdit::textChanged, this, &CGridSetRef::sigChanged); ++ connect(lineNorthing, &QLineEdit::textChanged, this, &CGridSetRef::sigChanged); ++ connect(lineHorizSpacing, &QLineEdit::textChanged, this, &CGridSetRef::sigChanged); ++ connect(lineVertSpacing, &QLineEdit::textChanged, this, &CGridSetRef::sigChanged); ++ connect(lineGridProj, &QLineEdit::textChanged, this, &CGridSetRef::sigChanged); ++ ++ labelHelp->setText(tr("Valid coordinate formats: If the projection is lat/lon all values have to be in degree, e.g. \"48.2\" or \"12.4\". " ++ "For all other projections values are either in multiple of meter or feet. If you are doing it wrong the entry field " ++ "will turn red." ++ )); ++ connect(CMainWindow::self().showToolHelp(), &QAction::toggled, labelHelp, &QLabel::setVisible); ++} ++ ++void CGridSetRef::saveSettings(QSettings& cfg) ++{ ++ cfg.setValue("proj", lineGridProj->text()); ++ cfg.setValue("easting", lineEasting->text().toDouble()); ++ cfg.setValue("northing", lineNorthing->text().toDouble()); ++ cfg.setValue("horizSpacing", lineHorizSpacing->text().toDouble()); ++ cfg.setValue("vertSpacing", lineVertSpacing->text().toDouble()); ++} ++ ++void CGridSetRef::loadSettings(QSettings& cfg) ++{ ++ lineGridProj->setText(cfg.value("proj","").toString()); ++ lineEasting->setText(cfg.value("easting","").toString()); ++ lineNorthing->setText(cfg.value("northing","").toString()); ++ lineHorizSpacing->setText(cfg.value("horizSpacing","").toString()); ++ lineVertSpacing->setText(cfg.value("vertSpacing","").toString()); ++ lineGridProj->setCursorPosition(0); ++} ++ ++ ++bool CGridSetRef::isOk() ++{ ++ bool allOk = true; ++ ++ bool ok = CProjWizard::validProjStr(lineGridProj->text()); ++ markWidget(lineGridProj, ok); ++ allOk &= ok; ++ ++ ok &= lineEasting->text().toDouble(&ok) != 0; ++ markWidget(lineEasting, ok); ++ allOk &= ok; ++ ++ ok &= lineNorthing->text().toDouble(&ok) != 0; ++ markWidget(lineNorthing, ok); ++ allOk &= ok; ++ ++ ok &= lineHorizSpacing->text().toDouble(&ok) != 0; ++ markWidget(lineHorizSpacing, ok); ++ allOk &= ok; ++ ++ ok &= lineVertSpacing->text().toDouble(&ok) != 0; ++ markWidget(lineVertSpacing, ok); ++ allOk &= ok; ++ ++ return allOk; ++} ++ ++void CGridSetRef::slotSetupGridProj() ++{ ++ CProjWizard dlg(*lineGridProj, this); ++ dlg.exec(); ++ lineGridProj->setCursorPosition(0); ++} ++ ++void CGridSetRef::slotReset() ++{ ++ lineGridProj->clear(); ++ lineEasting->clear(); ++ lineNorthing->clear(); ++ lineHorizSpacing->clear(); ++ lineVertSpacing->clear(); ++} +diff --git a/src/qmaptool/overlay/gridtool/CGridSetRef.h b/src/qmaptool/overlay/gridtool/CGridSetRef.h +new file mode 100644 +index 00000000..7956b0d3 +--- /dev/null ++++ b/src/qmaptool/overlay/gridtool/CGridSetRef.h +@@ -0,0 +1,86 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CGRIDSETREF_H ++#define CGRIDSETREF_H ++ ++#include "ui_IGridSetRef.h" ++ ++class QSettings; ++ ++class CGridSetRef : public QWidget, private Ui::IGridSetRef ++{ ++ Q_OBJECT ++public: ++ CGridSetRef(QWidget * parent); ++ virtual ~CGridSetRef() = default; ++ ++ void saveSettings(QSettings& cfg); ++ void loadSettings(QSettings& cfg); ++ ++ bool isOk(); ++ ++ QString getProjection() const ++ { ++ return lineGridProj->text(); ++ } ++ ++ qreal getEasting() const ++ { ++ return lineEasting->text().toDouble(); ++ } ++ ++ qreal getNorthing() const ++ { ++ return lineNorthing->text().toDouble(); ++ } ++ ++ qreal getHorizSpacing() const ++ { ++ return lineHorizSpacing->text().toDouble(); ++ } ++ ++ qreal getVertSpacing() const ++ { ++ return lineVertSpacing->text().toDouble(); ++ } ++ ++signals: ++ void sigChanged(); ++ ++public slots: ++ void slotReset(); ++ ++private slots: ++ void slotSetupGridProj(); ++ ++private: ++ template ++ void markWidget(T * w, bool isOk) ++ { ++ QPalette pal = T(this).palette(); ++ if(!isOk) ++ { ++ pal.setColor(QPalette::Base, "#ffaa7f"); ++ } ++ w->setPalette(pal); ++ } ++}; ++ ++#endif //CGRIDSETREF_H ++ +diff --git a/src/qmaptool/overlay/gridtool/IGridPlacer.ui b/src/qmaptool/overlay/gridtool/IGridPlacer.ui +new file mode 100644 +index 00000000..833585ad +--- /dev/null ++++ b/src/qmaptool/overlay/gridtool/IGridPlacer.ui +@@ -0,0 +1,248 @@ ++ ++ ++ IGridPlacer ++ ++ ++ ++ 0 ++ 0 ++ 254 ++ 224 ++ ++ ++ ++ Form ++ ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ :/pic/line_3px_horizontal.png ++ ++ ++ Qt::AlignCenter ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ :/pic/line_3px_vertical.png ++ ++ ++ Qt::AlignCenter ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ :/pic/line_3px_vertical.png ++ ++ ++ Qt::AlignCenter ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ 40 ++ 20 ++ ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ Reset ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ :/pic/line_3px_horizontal.png ++ ++ ++ Qt::AlignCenter ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Set Area ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/src/qmaptool/overlay/gridtool/IGridSelArea.ui b/src/qmaptool/overlay/gridtool/IGridSelArea.ui +new file mode 100644 +index 00000000..dd3f4a04 +--- /dev/null ++++ b/src/qmaptool/overlay/gridtool/IGridSelArea.ui +@@ -0,0 +1,49 @@ ++ ++ ++ IGridSelArea ++ ++ ++ ++ 0 ++ 0 ++ 400 ++ 300 ++ ++ ++ ++ Form ++ ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ ++ ++ TextLabel ++ ++ ++ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/src/qmaptool/overlay/gridtool/IGridSetRef.ui b/src/qmaptool/overlay/gridtool/IGridSetRef.ui +new file mode 100644 +index 00000000..68fe4d31 +--- /dev/null ++++ b/src/qmaptool/overlay/gridtool/IGridSetRef.ui +@@ -0,0 +1,117 @@ ++ ++ ++ IGridSetRef ++ ++ ++ ++ 0 ++ 0 ++ 400 ++ 133 ++ ++ ++ ++ Form ++ ++ ++ ++ 3 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ ++ ++ Grid Projection: ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/GridWizard.png:/icons/32x32/GridWizard.png ++ ++ ++ ++ ++ ++ ++ ++ ++ TextLabel ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ ++ ++ Easting ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Horiz. Spacing ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Northing ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Vert. Spacing ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/src/qmaptool/overlay/refmap/CDialogRefPoint.cpp b/src/qmaptool/overlay/refmap/CDialogRefPoint.cpp +new file mode 100644 +index 00000000..895ef920 +--- /dev/null ++++ b/src/qmaptool/overlay/refmap/CDialogRefPoint.cpp +@@ -0,0 +1,74 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "overlay/refmap/CDialogRefPoint.h" ++#include "units/IUnit.h" ++ ++#include ++ ++CDialogRefPoint::CDialogRefPoint(QPointF& ptPtx, QPointF& ptRef, QWidget *parent) ++ : QDialog(parent) ++ , ptPtx(ptPtx) ++ , ptRef(ptRef) ++{ ++ setupUi(this); ++ connect(lineCoord, &QLineEdit::textEdited, this, &CDialogRefPoint::slotEditPosition); ++ ++ lineX->setText(QString::number(qRound(ptPtx.x()))); ++ lineY->setText(QString::number(qRound(ptPtx.y()))); ++ if(ptRef != NOPOINTF) ++ { ++ QString str; ++ if(IUnit::degToStr(ptRef.x(), ptRef.y(), str)) ++ { ++ str = tr("bad coordinate"); ++ } ++ lineCoord->setText(str); ++ } ++ ++ labelWarning->hide(); ++} ++ ++void CDialogRefPoint::slotEditPosition(const QString& str) ++{ ++ labelWarning->setVisible(!IUnit::isValidCoordString(str)); ++} ++ ++void CDialogRefPoint::accept() ++{ ++ bool ok; ++ ptPtx.setX(lineX->text().toInt(&ok)); ++ if(!ok) ++ { ++ QMessageBox::warning(this, tr("Error"), tr("Bad value for X pixel."), QMessageBox::Ok); ++ return; ++ } ++ ptPtx.setY(lineY->text().toInt(&ok)); ++ if(!ok) ++ { ++ QMessageBox::warning(this, tr("Error"), tr("Bad value for Y pixel."), QMessageBox::Ok); ++ return; ++ } ++ ++ if(!IUnit::strToDeg(lineCoord->text(), ptRef.rx(), ptRef.ry())) ++ { ++ return; ++ } ++ ++ QDialog::accept(); ++} +diff --git a/src/qmaptool/overlay/refmap/CDialogRefPoint.h b/src/qmaptool/overlay/refmap/CDialogRefPoint.h +new file mode 100644 +index 00000000..67bc5df5 +--- /dev/null ++++ b/src/qmaptool/overlay/refmap/CDialogRefPoint.h +@@ -0,0 +1,46 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CDIALOGREFPOINT_H ++#define CDIALOGREFPOINT_H ++ ++#include "ui_IDialogRefPoint.h" ++#include ++ ++class QPointF; ++ ++class CDialogRefPoint : public QDialog, private Ui::IDialogRefPoint ++{ ++ Q_OBJECT ++public: ++ CDialogRefPoint(QPointF& ptPtx, QPointF& ptRef, QWidget * parent); ++ virtual ~CDialogRefPoint() = default; ++ ++public slots: ++ void accept() override; ++ ++private slots: ++ void slotEditPosition(const QString& str); ++ ++private: ++ QPointF& ptPtx; ++ QPointF& ptRef; ++}; ++ ++#endif //CDIALOGREFPOINT_H ++ +diff --git a/src/qmaptool/overlay/refmap/COverlayRefMapPoint.cpp b/src/qmaptool/overlay/refmap/COverlayRefMapPoint.cpp +new file mode 100644 +index 00000000..eae52331 +--- /dev/null ++++ b/src/qmaptool/overlay/refmap/COverlayRefMapPoint.cpp +@@ -0,0 +1,52 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "overlay/refmap/COverlayRefMapPoint.h" ++#include "units/IUnit.h" ++ ++COverlayRefMapPoint::COverlayRefMapPoint(qint32 cnt, const QPointF &ptRef, const QPointF &ptPtx, QTreeWidget *parent) ++ : QTreeWidgetItem(parent) ++{ ++ setText(eColumnCnt, QString::number(cnt)); ++ setPtPtx(ptPtx); ++ setPtRef(ptRef); ++} ++ ++void COverlayRefMapPoint::setPtPtx(const QPointF& pt) ++{ ++ ptPtx.rx() = qRound(pt.x()); ++ ptPtx.ry() = qRound(pt.y()); ++ setText(eColumnXY, QString("%1, %2").arg(ptPtx.x()).arg(ptPtx.y())); ++} ++ ++void COverlayRefMapPoint::setPtRef(const QPointF& pt) ++{ ++ ptRef = pt; ++ QString str; ++ if(!IUnit::self().degToStr(ptRef.x(), ptRef.y(), str)) ++ { ++ str = tr("bad coordinate"); ++ } ++ setText(eColumnLonLat, str); ++} ++ ++void COverlayRefMapPoint::setIndex(int n) ++{ ++ setText(eColumnCnt, QString::number(n)); ++} ++ +diff --git a/src/qmaptool/overlay/refmap/COverlayRefMapPoint.h b/src/qmaptool/overlay/refmap/COverlayRefMapPoint.h +new file mode 100644 +index 00000000..53bced7c +--- /dev/null ++++ b/src/qmaptool/overlay/refmap/COverlayRefMapPoint.h +@@ -0,0 +1,67 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef COVERLAYREFMAPPOINT_H ++#define COVERLAYREFMAPPOINT_H ++ ++#include ++#include ++ ++class COverlayRefMapPoint : public QTreeWidgetItem ++{ ++ Q_DECLARE_TR_FUNCTIONS(COverlayRefMapPoint) ++public: ++ COverlayRefMapPoint(qint32 cnt, const QPointF& ptRef, const QPointF& ptPtx, QTreeWidget * parent); ++ virtual ~COverlayRefMapPoint() = default; ++ ++ enum column_e ++ { ++ eColumnCnt ++ , eColumnXY ++ , eColumnLonLat ++ }; ++ ++ void setPtPtx(const QPointF& pt); ++ void setPtRef(const QPointF& pt); ++ void setIndex(int n); ++ ++ const QPointF& getPtPtx() const ++ { ++ return ptPtx; ++ } ++ ++ const QPointF& getPtRef() const ++ { ++ return ptRef; ++ } ++ ++ bool operator<(const QTreeWidgetItem& p) const override ++ { ++ const COverlayRefMapPoint& pt = dynamic_cast(p); ++ qreal v1 = ptPtx.y() * 1000000000 + ptPtx.x(); ++ qreal v2 = pt.ptPtx.y() * 1000000000 + pt.ptPtx.x(); ++ return v1 < v2; ++ } ++ ++private: ++ QPointF ptRef; ++ QPointF ptPtx; ++}; ++ ++#endif //COVERLAYREFMAPPOINT_H ++ +diff --git a/src/qmaptool/overlay/refmap/CProjWizard.cpp b/src/qmaptool/overlay/refmap/CProjWizard.cpp +new file mode 100644 +index 00000000..2f325932 +--- /dev/null ++++ b/src/qmaptool/overlay/refmap/CProjWizard.cpp +@@ -0,0 +1,237 @@ ++/********************************************************************************************** ++ Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "CMainWindow.h" ++#include "helpers/mitab.h" ++#include "overlay/refmap/CProjWizard.h" ++ ++#include ++#include ++ ++struct mitab_entry_t ++{ ++ QString name; ++ int idx; ++}; ++ ++static bool mitabLessThan(const mitab_entry_t &s1, const mitab_entry_t &s2) ++{ ++ return s1.name < s2.name; ++} ++ ++CProjWizard::CProjWizard(QLineEdit &line, QWidget * parent) ++ : QDialog(parent) ++ , line(line) ++{ ++ setupUi(this); ++ QList list; ++ int idx = 0; ++ const MapInfoDatumInfo * di = asDatumInfoListQL; ++ ++ while(di->nMapInfoDatumID != -1) ++ { ++ mitab_entry_t entry; ++ entry.name = di->pszOGCDatumName; ++ entry.idx = idx; ++ list << entry; ++ ++di; ++ ++idx; ++ } ++ qSort(list.begin(), list.end(), mitabLessThan); ++ ++ for(const mitab_entry_t &entry : list) ++ { ++ comboDatum->addItem(entry.name, entry.idx); ++ } ++ ++ comboHemisphere->addItem(tr("north"), ""); ++ comboHemisphere->addItem(tr("south"), "+south"); ++ ++ connect(radioMercator, &QRadioButton::clicked, this, &CProjWizard::slotChange); ++ connect(radioWorldMercator, &QRadioButton::clicked, this, &CProjWizard::slotChange); ++ connect(radioUPSNorth, &QRadioButton::clicked, this, &CProjWizard::slotChange); ++ connect(radioUPSSouth, &QRadioButton::clicked, this, &CProjWizard::slotChange); ++ connect(radioUTM, &QRadioButton::clicked, this, &CProjWizard::slotChange); ++ connect(radioUserDef, &QRadioButton::clicked, this, &CProjWizard::slotChange); ++ connect(lineUserDef, &QLineEdit::textChanged, this, &CProjWizard::slotChange); ++ ++ connect(spinUTMZone, static_cast(&QSpinBox::valueChanged), this, &CProjWizard::slotChange); ++ connect(comboDatum, static_cast(&QComboBox::currentIndexChanged), this, &CProjWizard::slotChange); ++ connect(comboHemisphere, static_cast(&QComboBox::currentIndexChanged), this, &CProjWizard::slotChange); ++ ++ QString projstr = line.text(); ++ QRegExp re2("\\s*\\+proj=merc \\+a=6378137 \\+b=6378137 \\+lat_ts=0.001 \\+lon_0=0.0 \\+x_0=0.0 \\+y_0=0 \\+k=1.0 \\+units=m \\+nadgrids=@null \\+no_defs"); ++ QRegExp re3("\\s*\\+proj=merc\\s(.*)"); ++ QRegExp re4("\\s*\\+proj=utm \\+zone=([0-9]+)\\s(.*)"); ++ ++ if(re2.exactMatch(projstr)) ++ { ++ radioWorldMercator->setChecked(true); ++ } ++ else if(re3.exactMatch(projstr)) ++ { ++ radioMercator->setChecked(true); ++ findDatum(re3.cap(1)); ++ } ++ else if(re4.exactMatch(projstr)) ++ { ++ radioUTM->setChecked(true); ++ spinUTMZone->setValue(re4.cap(1).toInt()); ++ ++ QString datum = re4.cap(2); ++ if(datum.startsWith("+south ")) ++ { ++ datum = datum.mid(7); ++ comboHemisphere->setCurrentIndex(1); ++ } ++ ++ findDatum(datum); ++ } ++ ++ slotChange(); ++} ++ ++CProjWizard::~CProjWizard() ++{ ++} ++ ++ ++void CProjWizard::findDatum(const QString& str) ++{ ++ QString cmp; ++ int idx = 0; ++ const MapInfoDatumInfo * di = asDatumInfoListQL; ++ ++ while(di->nMapInfoDatumID != -1) ++ { ++ cmp.clear(); ++ if(di->pszOGCDatumName != QString()) ++ { ++ const MapInfoSpheroidInfo * si = asSpheroidInfoList; ++ while(si->nMapInfoId != -1) ++ { ++ if(si->nMapInfoId == di->nEllipsoid) ++ { ++ break; ++ } ++ ++si; ++ } ++ ++ cmp += QString("+a=%1 +b=%2 ").arg(si->dfA,0,'f',4).arg(si->dfA * (1.0 - (1.0/si->dfInvFlattening)),0,'f',4); ++ cmp += QString("+towgs84=%1,%2,%3,%4,%5,%6,%7,%8 ").arg(di->dfShiftX).arg(di->dfShiftY).arg(di->dfShiftZ).arg(di->dfDatumParm0).arg(di->dfDatumParm1).arg(di->dfDatumParm2).arg(di->dfDatumParm3).arg(di->dfDatumParm4); ++ cmp += "+units=m +no_defs"; ++ } ++ ++ if(cmp == str) ++ { ++ comboDatum->setCurrentIndex(comboDatum->findText(di->pszOGCDatumName)); ++ break; ++ } ++ ++ ++di; ++ ++idx; ++ } ++} ++ ++ ++void CProjWizard::slotChange() ++{ ++ QString str; ++ if(radioMercator->isChecked()) ++ { ++ str += "+proj=merc "; ++ } ++ else if(radioWorldMercator->isChecked()) ++ { ++ str += "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.001 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs"; ++ labelResult->setText(str); ++ return; ++ } ++ else if(radioUPSNorth->isChecked()) ++ { ++ str += "+init=epsg:32661"; ++ } ++ else if(radioUPSSouth->isChecked()) ++ { ++ str += "+init=epsg:32761"; ++ } ++ else if(radioUTM->isChecked()) ++ { ++ str += QString("+proj=utm +zone=%1 %2 ").arg(spinUTMZone->value()).arg(comboHemisphere->itemData(comboHemisphere->currentIndex()).toString()); ++ } ++ else if(radioUserDef->isChecked()) ++ { ++ str += lineUserDef->text() + " "; ++ } ++ ++ int idx = comboDatum->itemData(comboDatum->currentIndex()).toInt(); ++ const MapInfoDatumInfo di = asDatumInfoListQL[idx]; ++ if(di.pszOGCDatumName != QString()) ++ { ++ const MapInfoSpheroidInfo * si = asSpheroidInfoList; ++ while(si->nMapInfoId != -1) ++ { ++ if(si->nMapInfoId == di.nEllipsoid) ++ { ++ break; ++ } ++ ++si; ++ } ++ ++ str += QString("+a=%1 +b=%2 ").arg(si->dfA,0,'f',4).arg(si->dfA * (1.0 - (1.0/si->dfInvFlattening)),0,'f',4); ++ str += QString("+towgs84=%1,%2,%3,%4,%5,%6,%7,%8 ").arg(di.dfShiftX).arg(di.dfShiftY).arg(di.dfShiftZ).arg(di.dfDatumParm0).arg(di.dfDatumParm1).arg(di.dfDatumParm2).arg(di.dfDatumParm3).arg(di.dfDatumParm4); ++ str += "+units=m +no_defs"; ++ } ++ ++ labelResult->setText(str); ++} ++ ++ ++void CProjWizard::accept() ++{ ++ if (CProjWizard::validProjStr(labelResult->text())) ++ { ++ line.setText(labelResult->text()); ++ line.setCursorPosition(0); ++ QDialog::accept(); ++ } ++} ++ ++ ++bool CProjWizard::validProjStr(const QString projStr) ++{ ++ if(projStr.isEmpty()) ++ { ++ return false; ++ } ++ ++ projPJ projCheck = pj_init_plus(projStr.toUtf8().data()); ++ ++ if (!projCheck) ++ { /* For some reason pj_errno does not work as expected in some versions of Visual Studio, so using pj_get_errno_ref instead */ ++ QMessageBox::warning(&CMainWindow::self(), tr("Error..."),tr("The value\n'%1'\nis not a valid coordinate system definition:\n%2").arg(projStr).arg(pj_strerrno(*pj_get_errno_ref())),QMessageBox::Abort,QMessageBox::Abort); ++ return false; ++ } ++ else ++ { ++ pj_free(projCheck); ++ return true; ++ } ++} ++ ++ +diff --git a/src/qmaptool/overlay/refmap/CProjWizard.h b/src/qmaptool/overlay/refmap/CProjWizard.h +new file mode 100644 +index 00000000..5cd1f38f +--- /dev/null ++++ b/src/qmaptool/overlay/refmap/CProjWizard.h +@@ -0,0 +1,44 @@ ++/********************************************************************************************** ++ Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CPROJWIZARD_H ++#define CPROJWIZARD_H ++ ++#include "ui_IProjWizard.h" ++#include ++ ++class CProjWizard : public QDialog, private Ui::IProjWizard ++{ ++ Q_OBJECT ++public: ++ CProjWizard(QLineEdit& line, QWidget *parent); ++ virtual ~CProjWizard(); ++ static bool validProjStr(const QString projStr); ++ ++public slots: ++ void accept() override; ++ void slotChange(); ++ ++private: ++ void findDatum(const QString& str); ++ ++ QLineEdit& line; ++}; ++ ++#endif //CPROJWIZARD_H ++ +diff --git a/src/qmaptool/overlay/refmap/IDialogRefPoint.ui b/src/qmaptool/overlay/refmap/IDialogRefPoint.ui +new file mode 100644 +index 00000000..7e1ecd4e +--- /dev/null ++++ b/src/qmaptool/overlay/refmap/IDialogRefPoint.ui +@@ -0,0 +1,131 @@ ++ ++ ++ IDialogRefPoint ++ ++ ++ ++ 0 ++ 0 ++ 510 ++ 191 ++ ++ ++ ++ Dialog ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Coord. Map File [pixel] ++ ++ ++ ++ ++ ++ ++ x ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ y ++ ++ ++ ++ ++ ++ ++ Coord. lat/lon WGS84 [°] ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Bad position format. Must be: ++"[N|S] ddd mm.sss [W|E] ddd mm.sss" ++or ++"[N|S] ddd.ddd [W|E] ddd.ddd" ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ ++ ++ Qt::Vertical ++ ++ ++ ++ 20 ++ 40 ++ ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ QDialogButtonBox::Cancel|QDialogButtonBox::Ok ++ ++ ++ ++ ++ ++ ++ ++ ++ buttonBox ++ accepted() ++ IDialogRefPoint ++ accept() ++ ++ ++ 248 ++ 254 ++ ++ ++ 157 ++ 274 ++ ++ ++ ++ ++ buttonBox ++ rejected() ++ IDialogRefPoint ++ reject() ++ ++ ++ 316 ++ 260 ++ ++ ++ 286 ++ 274 ++ ++ ++ ++ ++ +diff --git a/src/qmaptool/overlay/refmap/IProjWizard.ui b/src/qmaptool/overlay/refmap/IProjWizard.ui +new file mode 100644 +index 00000000..3f78eec9 +--- /dev/null ++++ b/src/qmaptool/overlay/refmap/IProjWizard.ui +@@ -0,0 +1,210 @@ ++ ++ ++ IProjWizard ++ ++ ++ ++ 0 ++ 0 ++ 440 ++ 280 ++ ++ ++ ++ Proj4 Wizard ++ ++ ++ ++ ++ ++ QFrame::StyledPanel ++ ++ ++ QFrame::Raised ++ ++ ++ ++ ++ ++ Mercator ++ ++ ++ ++ ++ ++ ++ ++ ++ UTM ++ ++ ++ ++ ++ ++ ++ zone ++ ++ ++ ++ ++ ++ ++ 1 ++ ++ ++ 60 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ 40 ++ 20 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ user defined ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Datum ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ World Mercator (OSM) ++ ++ ++ ++ ++ ++ ++ Qt::Vertical ++ ++ ++ ++ 20 ++ 40 ++ ++ ++ ++ ++ ++ ++ ++ Result: ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ UPS North (North Pole) ++ ++ ++ ++ ++ ++ ++ UPS South (South Pole) ++ ++ ++ ++ ++ ++ ++ Projection ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ QDialogButtonBox::Cancel|QDialogButtonBox::Ok ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ buttonBox ++ accepted() ++ IProjWizard ++ accept() ++ ++ ++ 248 ++ 254 ++ ++ ++ 157 ++ 274 ++ ++ ++ ++ ++ buttonBox ++ rejected() ++ IProjWizard ++ reject() ++ ++ ++ 316 ++ 260 ++ ++ ++ 286 ++ 274 ++ ++ ++ ++ ++ +diff --git a/src/qmaptool/resources.qrc b/src/qmaptool/resources.qrc +new file mode 100644 +index 00000000..9dc34535 +--- /dev/null ++++ b/src/qmaptool/resources.qrc +@@ -0,0 +1,93 @@ ++ ++ ++ ../animation/loader.gif ++ ++ ../cursors/cursorPointAdd.png ++ ../cursors/cursorPointDel.png ++ ../cursors/cursorPointMove.png ++ ++ ../icons/32x32/AddOverview.png ++ ../icons/32x32/Add.png ++ ../icons/32x32/Apply.png ++ ../icons/32x32/Cancel.png ++ ../icons/32x32/Check.png ++ ../icons/32x32/CombineMap.png ++ ../icons/32x32/CutMap.png ++ ../icons/32x32/DeleteMultiple.png ++ ../icons/32x32/DeleteOne.png ++ ../icons/32x32/Export.png ++ ../icons/32x32/FolderMap.png ++ ../icons/32x32/GridTool.png ++ ../icons/32x32/GridWizard.png ++ ../icons/32x32/Info.png ++ ../icons/32x32/LoadGcp.png ++ ../icons/32x32/LoadShape.png ++ ../icons/32x32/MapLayer.png ++ ../icons/32x32/MouseWheel.png ++ ../icons/32x32/MoveArrow.png ++ ../icons/32x32/PathBlue.png ++ ../icons/32x32/PointAdd.png ++ ../icons/32x32/PointDelAll.png ++ ../icons/32x32/PointDel.png ++ ../icons/32x32/PointMove.png ++ ../icons/32x32/QMapTool.png ++ ../icons/32x32/Rasterize.png ++ ../icons/32x32/RefAdd.png ++ ../icons/32x32/RefDelAll.png ++ ../icons/32x32/RefDel.png ++ ../icons/32x32/ReferenceMap.png ++ ../icons/32x32/RefMoveAuto.png ++ ../icons/32x32/RefMove.png ++ ../icons/32x32/Reload.png ++ ../icons/32x32/Reset.png ++ ../icons/32x32/SaveGcp.png ++ ../icons/32x32/SaveShape.png ++ ../icons/32x32/SetupCoordFormat.png ++ ../icons/32x32/Sort.png ++ ../icons/32x32/UnitSetup.png ++ ++ ../icons/48x48/AddOverview.png ++ ../icons/48x48/Add.png ++ ../icons/48x48/Apply.png ++ ../icons/48x48/Cancel.png ++ ../icons/48x48/Check.png ++ ../icons/48x48/CombineMap.png ++ ../icons/48x48/CutMap.png ++ ../icons/48x48/DeleteMultiple.png ++ ../icons/48x48/DeleteOne.png ++ ../icons/48x48/Export.png ++ ../icons/48x48/FolderMap.png ++ ../icons/48x48/GridTool.png ++ ../icons/48x48/GridWizard.png ++ ../icons/48x48/Info.png ++ ../icons/48x48/LoadGcp.png ++ ../icons/48x48/LoadShape.png ++ ../icons/48x48/MapLayer.png ++ ../icons/48x48/MouseWheel.png ++ ../icons/48x48/MoveArrow.png ++ ../icons/48x48/PathBlue.png ++ ../icons/48x48/PointAdd.png ++ ../icons/48x48/PointDelAll.png ++ ../icons/48x48/PointDel.png ++ ../icons/48x48/PointMove.png ++ ../icons/48x48/QMapTool.png ++ ../icons/48x48/Rasterize.png ++ ../icons/48x48/RefAdd.png ++ ../icons/48x48/RefDelAll.png ++ ../icons/48x48/RefDel.png ++ ../icons/48x48/ReferenceMap.png ++ ../icons/48x48/RefMoveAuto.png ++ ../icons/48x48/RefMove.png ++ ../icons/48x48/Reload.png ++ ../icons/48x48/Reset.png ++ ../icons/48x48/SaveGcp.png ++ ../icons/48x48/SaveShape.png ++ ../icons/48x48/SetupCoordFormat.png ++ ../icons/48x48/Sort.png ++ ../icons/48x48/UnitSetup.png ++ ++ pic/line_3px_horizontal.png ++ pic/line_3px_vertical.png ++ pic/splash.png ++ ++ +diff --git a/src/qmaptool/setup/CAppOpts.h b/src/qmaptool/setup/CAppOpts.h +new file mode 100644 +index 00000000..88992b17 +--- /dev/null ++++ b/src/qmaptool/setup/CAppOpts.h +@@ -0,0 +1,47 @@ ++/********************************************************************************************** ++ Copyright (C) 2009 Joerg Wunsch ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++#ifndef CAPPOPTS_H ++#define CAPPOPTS_H ++/* ++ * This class holds the options passed from the command-line, ++ * including the positional arguments. ++ */ ++ ++#include ++ ++class CAppOpts ++{ ++public: ++ const bool debug; // -d, print debug messages ++ const bool logfile; // -f, print debug messages to logfile ++ const bool nosplash; // -n, do not display splash screen ++ const QString configfile; ++ const QStringList arguments; ++ ++ CAppOpts(bool doDebug, bool doLogfile, bool noSplash, const QString& config, const QStringList& args) ++ : debug(doDebug) ++ , logfile(doLogfile) ++ , nosplash(noSplash) ++ , configfile(config) ++ , arguments(args) ++ { ++ } ++}; ++ ++extern CAppOpts *qlOpts; ++#endif //CAPPOPTS_H +diff --git a/src/qmaptool/setup/CAppSetupLinux.cpp b/src/qmaptool/setup/CAppSetupLinux.cpp +new file mode 100644 +index 00000000..e2d012d8 +--- /dev/null ++++ b/src/qmaptool/setup/CAppSetupLinux.cpp +@@ -0,0 +1,62 @@ ++/********************************************************************************************** ++ Copyright (C) 2015 Ivo Kronenberg ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "config.h" ++#include "setup/CAppSetupLinux.h" ++ ++#ifndef _MKSTR_1 ++#define _MKSTR_1(x) #x ++#define _MKSTR(x) _MKSTR_1(x) ++#endif ++ ++void CAppSetupLinux::initQMapTool() ++{ ++ prepareGdal("", ""); ++ ++ // setup translators ++ QString resourceDir = QLibraryInfo::location(QLibraryInfo::TranslationsPath); ++ QString translationPath = QCoreApplication::applicationDirPath(); ++ translationPath.replace(QRegExp("bin$"), "share/qmaptool/translations"); ++ prepareTranslator(resourceDir, "qt_"); ++ prepareTranslator(translationPath, "qmaptool_"); ++ ++ // create directories ++ IAppSetup::path(logDir(), 0, true, "LOG"); ++ ++ prepareToolPaths(); ++} ++ ++ ++ ++QString CAppSetupLinux::defaultCachePath() ++{ ++ return IAppSetup::path(QDir::home().absolutePath(), ".QMapTool/", false, 0); ++} ++ ++ ++QString CAppSetupLinux::userDataPath(QString subdir) ++{ ++ QString path = QDir::home().absoluteFilePath(CONFIGDIR); ++ return IAppSetup::path(path, subdir, false, 0); ++} ++ ++ ++QString CAppSetupLinux::logDir() ++{ ++ return QDir::temp().absolutePath(); ++} +diff --git a/src/qmaptool/setup/CAppSetupLinux.h b/src/qmaptool/setup/CAppSetupLinux.h +new file mode 100644 +index 00000000..a0d26b45 +--- /dev/null ++++ b/src/qmaptool/setup/CAppSetupLinux.h +@@ -0,0 +1,44 @@ ++/********************************************************************************************** ++ Copyright (C) 2015 Ivo Kronenberg ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CAPPSETUPLINUX_H ++#define CAPPSETUPLINUX_H ++ ++#include "setup/IAppSetup.h" ++ ++#include ++ ++class CAppSetupLinux : public IAppSetup ++{ ++public: ++ CAppSetupLinux(QObject * parent) ++ : IAppSetup(parent) ++ { ++ } ++ ++ ~CAppSetupLinux() = default; ++ void initQMapTool() override; ++ ++ QString defaultCachePath() override; ++ QString userDataPath(QString subdir = 0) override; ++ QString logDir() override; ++ QString findExecutable(const QString &name) override { return QStandardPaths::findExecutable(name); } ++}; ++ ++ ++#endif // CAPPSETUPLINUX_H +diff --git a/src/qmaptool/setup/CAppSetupMac.cpp b/src/qmaptool/setup/CAppSetupMac.cpp +new file mode 100644 +index 00000000..8d7ab0a2 +--- /dev/null ++++ b/src/qmaptool/setup/CAppSetupMac.cpp +@@ -0,0 +1,140 @@ ++/********************************************************************************************** ++ Copyright (C) 2015 Ivo Kronenberg ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "setup/CAppSetupMac.h" ++ ++static QString relTranslationDir = "Resources/translations"; // app ++static QString relGdalDir = "Resources/gdal"; // app ++static QString relProjDir = "Resources/proj"; // app ++static QString relBinDir = "Tools"; // app ++ ++static QString relLogDir = "Library/Logs"; // home ++ ++ ++void CAppSetupMac::extendPath() ++{ ++ QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); ++ QStringList envlist = env.toStringList(); ++ QString value = ""; ++ for(int i=0; i < envlist.size(); i++) ++ { ++ QString entry = envlist[i]; ++ if(entry.startsWith("PATH=")) ++ { ++ int index = entry.indexOf("="); ++ ++ if(index != -1) ++ { ++ value = entry.right(entry.length() - (index+1)) + ":"; ++ } ++ break; ++ } ++ } ++ QString binDir = getApplicationDir(relBinDir).absolutePath(); ++ qDebug() << "BIN" << binDir; ++ value += binDir; ++ qputenv("PATH", value.toLatin1().constData()); ++ ++ prepareToolPaths(); ++} ++ ++ ++void CAppSetupMac::initQMapTool() ++{ ++ extendPath(); ++ // setup gdal ++ QString gdalDir = getApplicationDir(relGdalDir).absolutePath(); ++ QString projDir = getApplicationDir(relProjDir).absolutePath(); ++ prepareGdal(gdalDir, projDir); ++ ++ // setup translators ++ QString translationPath = getApplicationDir(relTranslationDir).absolutePath(); ++ prepareTranslator(translationPath, "qt_"); ++ prepareTranslator(translationPath, "qmaptool_"); ++ ++ migrateDirContent(defaultCachePath()); ++ migrateDirContent(userDataPath()); ++ ++ // create directories ++ IAppSetup::path(logDir(), 0, false, "LOG"); ++} ++ ++ ++QString CAppSetupMac::defaultCachePath() ++{ ++ QString cachePath = QStandardPaths::standardLocations(QStandardPaths::CacheLocation).first(); ++ return IAppSetup::path(cachePath, 0, false, 0); ++} ++ ++ ++QString CAppSetupMac::userDataPath(QString subdir) ++{ ++#if QT_VERSION >= 0x050400 ++ QString dataDir = QStandardPaths::standardLocations(QStandardPaths::AppLocalDataLocation).first(); ++#else ++ QString dataDir = QStandardPaths::standardLocations(QStandardPaths::DataLocation).first(); ++#endif ++ return IAppSetup::path(dataDir, subdir, false, 0); ++} ++ ++ ++QString CAppSetupMac::logDir() ++{ ++ // home location returns / (root) instead of user home... ++ QString home = QStandardPaths::standardLocations(QStandardPaths::DesktopLocation).first(); ++ QDir dir = QDir(home); ++ dir.cdUp(); ++ return IAppSetup::path(dir.absolutePath(), relLogDir, false, 0); ++} ++ ++ ++QDir CAppSetupMac::getApplicationDir(QString subdir) ++{ ++ QDir appDir(QCoreApplication::applicationDirPath()); ++ appDir.cdUp(); ++ appDir.cd(subdir); ++ return appDir; ++} ++ ++ ++void CAppSetupMac::migrateDirContent(QString dest) ++{ ++ QString src = dest; ++ src.replace("/QLandkarte/", "/"); ++ QDir dirDest = QDir(dest); ++ QDir dirSource = QDir(src); ++ ++ if (!dirDest.exists() && dirSource.exists()) ++ { ++ qDebug() << "src directory for migration" << src; ++ qDebug() << "dst directory for migration" << dest; ++ ++ QDir wdir; ++ QString newdir = dest; ++ newdir.remove("/QMapTool"); ++ wdir.mkdir(newdir); ++ qDebug() << "directory created" << newdir; ++ ++ qDebug() << "migrate data from "<. ++ ++**********************************************************************************************/ ++ ++#ifndef CAPPSETUPMAC_H ++#define CAPPSETUPMAC_H ++ ++#include "setup/IAppSetup.h" ++ ++#include ++ ++ ++class CAppSetupMac : public IAppSetup ++{ ++public: ++ CAppSetupMac(QObject * parent) ++ : IAppSetup(parent) ++ { ++ } ++ ++ ~CAppSetupMac() = default; ++ void initQMapTool() override; ++ ++ QString defaultCachePath() override; ++ QString userDataPath(QString subdir = 0) override; ++ QString logDir() override; ++ QString findExecutable(const QString &name) override { return QStandardPaths::findExecutable(name); } ++ ++private: ++ QDir getApplicationDir(QString subdir); ++ void migrateDirContent(QString dest); ++ void extendPath(); ++}; ++ ++#endif // CAPPSETUPMAC_H +diff --git a/src/qmaptool/setup/CAppSetupWin.cpp b/src/qmaptool/setup/CAppSetupWin.cpp +new file mode 100644 +index 00000000..ede10da7 +--- /dev/null ++++ b/src/qmaptool/setup/CAppSetupWin.cpp +@@ -0,0 +1,69 @@ ++/********************************************************************************************** ++ Copyright (C) 2015 Ivo Kronenberg ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "config.h" ++#include "setup/CAppSetupWin.h" ++ ++ ++void CAppSetupWin::initQMapTool() ++{ ++ // setup environment variables for GDAL/Proj4 ++ QString apppath = QCoreApplication::applicationDirPath(); ++ apppath = apppath.replace("/", "\\"); ++ QString gdalDir = QString("%1\\data").arg(apppath); ++ QString projDir = QString("%1\\share\\proj").arg(apppath); ++ ++ qunsetenv("GDAL_DRIVER_PATH"); ++ prepareGdal(gdalDir, projDir); ++ ++ QString appResourceDir = QString("%1\\translations").arg(apppath).toUtf8(); ++ prepareTranslator(appResourceDir, "qtbase_"); ++ prepareTranslator(appResourceDir, "qmaptool_"); ++ ++ // limit PATH to application directory in order to avoid that wrong .dll's are loaded ++ path = apppath.toUtf8(); ++ qputenv("PATH", path); ++ ++ // create directories ++ IAppSetup::path(logDir(), 0, true, "LOG"); ++ ++ prepareToolPaths(); ++} ++ ++QString CAppSetupWin::defaultCachePath() ++{ ++ return IAppSetup::path(QDir::home().absolutePath(), ".QMapTool/", false, 0); ++} ++ ++ ++QString CAppSetupWin::userDataPath(QString subdir) ++{ ++ QString path = QDir::home().absoluteFilePath(CONFIGDIR); ++ return IAppSetup::path(path, subdir, false, 0); ++} ++ ++ ++QString CAppSetupWin::logDir() ++{ ++ return QDir::temp().absolutePath(); ++} ++ ++QString CAppSetupWin::findExecutable(const QString &name) ++{ ++ return QStandardPaths::findExecutable(name); ++} +diff --git a/src/qmaptool/setup/CAppSetupWin.h b/src/qmaptool/setup/CAppSetupWin.h +new file mode 100644 +index 00000000..4ef0043e +--- /dev/null ++++ b/src/qmaptool/setup/CAppSetupWin.h +@@ -0,0 +1,45 @@ ++/********************************************************************************************** ++ Copyright (C) 2015 Ivo Kronenberg ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CAPPSETUPWIN_H ++#define CAPPSETUPWIN_H ++ ++#include "setup/IAppSetup.h" ++ ++#include ++ ++class CAppSetupWin : public IAppSetup ++{ ++public: ++ CAppSetupWin(QObject * parent) ++ : IAppSetup(parent) ++ { ++ } ++ ++ ~CAppSetupWin() = default; ++ void initQMapTool() override; ++ ++ QString defaultCachePath() override; ++ QString userDataPath(QString subdir = 0) override; ++ QString logDir() override; ++ QString findExecutable(const QString &name) override; ++ ++ QByteArray path; ++}; ++ ++#endif // CAPPSETUPWIN_H +diff --git a/src/qmaptool/setup/CCommandProcessor.cpp b/src/qmaptool/setup/CCommandProcessor.cpp +new file mode 100644 +index 00000000..b0cf6519 +--- /dev/null ++++ b/src/qmaptool/setup/CCommandProcessor.cpp +@@ -0,0 +1,58 @@ ++/********************************************************************************************** ++ Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "setup/CCommandProcessor.h" ++ ++#include ++#include ++#include ++ ++ ++CAppOpts* CCommandProcessor::processOptions(const QStringList &arguments) ++{ ++ QCommandLineParser parser; ++ QCommandLineOption helpOption = parser.addHelpOption(); // h help ++ ++ QCommandLineOption debugOption(QStringList() << "d" << "debug", tr("Print debug output to console.")); ++ parser.addOption(debugOption); ++ ++ QCommandLineOption logfileOption(QStringList() << "f" << "logfile", tr("Print debug output to logfile (temp. path).")); ++ parser.addOption(logfileOption); ++ ++ QCommandLineOption nosplashOption(QStringList() << "n" << "no-splash", tr("Do not show splash screen.")); ++ parser.addOption(nosplashOption); ++ ++ QCommandLineOption configOption(QStringList() << "c" << "config", tr("File with QMapTool configuration."), tr("file")); ++ parser.addOption(configOption); ++ ++ //parser.addPositionalArgument("files", tr("Files for future use.")); ++ ++ if (!parser.parse(arguments)) ++ { ++ std::cerr << parser.errorText().toUtf8().constData(); ++ std::cerr << parser.helpText().toUtf8().constData(); ++ exit(1); ++ } ++ if (parser.isSet(helpOption)) ++ { ++ std::cout << parser.helpText().toUtf8().constData(); ++ exit(0); ++ } ++ ++ return new CAppOpts(parser.isSet(debugOption), parser.isSet(logfileOption), parser.isSet(nosplashOption), parser.value(configOption), parser.positionalArguments()); ++} +diff --git a/src/qmaptool/setup/CCommandProcessor.h b/src/qmaptool/setup/CCommandProcessor.h +new file mode 100644 +index 00000000..55a41e8f +--- /dev/null ++++ b/src/qmaptool/setup/CCommandProcessor.h +@@ -0,0 +1,33 @@ ++/********************************************************************************************** ++ Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CCOMMANDPROCESSOR_H ++#define CCOMMANDPROCESSOR_H ++ ++#include "setup/CAppOpts.h" ++#include ++ ++class CCommandProcessor ++{ ++ Q_DECLARE_TR_FUNCTIONS(CCommandProcessor) ++public: ++ CAppOpts* processOptions(const QStringList &arguments); ++}; ++ ++ ++#endif // CCOMMANDPROCESSOR_H +diff --git a/src/qmaptool/setup/CLogHandler.cpp b/src/qmaptool/setup/CLogHandler.cpp +new file mode 100644 +index 00000000..41b87cc2 +--- /dev/null ++++ b/src/qmaptool/setup/CLogHandler.cpp +@@ -0,0 +1,122 @@ ++/********************************************************************************************** ++ Copyright (C) 2015 Ivo Kronenberg ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "setup/CLogHandler.h" ++#include ++ ++ ++CLogHandler::CLogHandler(QString logDirectory, bool writeToFile, bool debugOutput) : ++ writeToFile(writeToFile), debugOutput(debugOutput), logFile(QDir(logDirectory).absoluteFilePath(logfileName())), ++ fileStream(&logFile) ++{ ++ if (writeToFile) ++ { ++ fileStream.setCodec("UTF-8"); ++ logFile.open(QIODevice::WriteOnly | QIODevice::Append); ++ } ++ qSetMessagePattern("%{time yyyy-MM-dd h:mm:ss.zzz} [%{type}] %{message}"); ++} ++ ++void CLogHandler::log(QtMsgType type, const QMessageLogContext &context, const QString &msg) ++{ ++#if QT_VERSION >= 0x050400 ++ QString txt = qFormatLogMessage(type, context, msg); ++#else ++ QString txt = msg; ++#endif ++ printToConsole(type, txt); ++ appendToFile(type, txt); ++} ++ ++void CLogHandler::printLoggerInfo() ++{ ++ qDebug() << "Log configuration:" << "log file=" << logFile.fileName() << "write to file=" << writeToFile << ++ "debug output=" << debugOutput; ++} ++ ++QString CLogHandler::logfileName() ++{ ++ QStringList domainSplit = QCoreApplication::organizationDomain().split("."); ++ QString fileName; ++ for(const QString &part : domainSplit) ++ { ++ fileName = fileName.insert(0, part + "."); ++ } ++ fileName.append(QCoreApplication::applicationName() + ".log"); ++ return fileName; ++} ++ ++ ++void CLogHandler::appendToFile(QtMsgType type, QString formatedMsg) ++{ ++ Q_UNUSED(type); ++ if (writeToFile) ++ { ++ fileStream << formatedMsg << endl; ++ } ++} ++ ++ ++void CLogHandler::printToConsole(QtMsgType type, QString formatedMsg) ++{ ++ switch (type) ++ { ++ case QtDebugMsg: ++ if (debugOutput) ++ { ++ std::cout << formatedMsg.toUtf8().constData() << std::endl; ++ } ++ break; ++ ++#if QT_VERSION >= 0x050500 ++ case QtInfoMsg: ++ std::cout << formatedMsg.toUtf8().constData() << std::endl; ++ break; ++ ++#endif ++ case QtWarningMsg: ++ std::cerr << formatedMsg.toUtf8().constData() << std::endl; ++ break; ++ ++ case QtCriticalMsg: ++ std::cerr << formatedMsg.toUtf8().constData() << std::endl; ++ break; ++ ++ case QtFatalMsg: ++ std::cerr << formatedMsg.toUtf8().constData() << std::endl; ++ abort(); ++ break; ++ } ++} ++ ++static CLogHandler* logHandler = nullptr; ++ ++static void logCallback(QtMsgType type, const QMessageLogContext &context, const QString &msg) ++{ ++ logHandler->log(type, context, msg); ++} ++ ++ ++void CLogHandler::initLogHandler(QString logDirectory, bool writeToFile, bool debugOutput) ++{ ++ logHandler = new CLogHandler(logDirectory, writeToFile, debugOutput); ++ qInstallMessageHandler(logCallback); ++ logHandler->printLoggerInfo(); ++} ++ ++ +diff --git a/src/qmaptool/setup/CLogHandler.h b/src/qmaptool/setup/CLogHandler.h +new file mode 100644 +index 00000000..f544e3e3 +--- /dev/null ++++ b/src/qmaptool/setup/CLogHandler.h +@@ -0,0 +1,47 @@ ++/********************************************************************************************** ++ Copyright (C) 2015 Ivo Kronenberg ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CLOGHANDLER_H ++#define CLOGHANDLER_H ++ ++#include ++ ++class CLogHandler ++{ ++public: ++ static void initLogHandler(QString logDirectory, bool writeToFile, bool debugOutput); ++ ++ void log(QtMsgType type, const QMessageLogContext &context, const QString &msg); ++ ++private: ++ CLogHandler(QString logDirectory, bool writeToFile, bool debugOutput); ++ void printLoggerInfo(); ++ ++ void appendToFile(QtMsgType type, QString formatedMsg); ++ void printToConsole(QtMsgType type, QString formatedMsg); ++ ++ QString logfileName(); ++ ++ bool writeToFile; ++ bool debugOutput; ++ QFile logFile; ++ QTextStream fileStream; ++}; ++ ++#endif // CLOGHANDLER_H ++ +diff --git a/src/qmaptool/setup/CSetupExtTools.cpp b/src/qmaptool/setup/CSetupExtTools.cpp +new file mode 100644 +index 00000000..54c37142 +--- /dev/null ++++ b/src/qmaptool/setup/CSetupExtTools.cpp +@@ -0,0 +1,93 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "setup/CSetupExtTools.h" ++#include "setup/IAppSetup.h" ++ ++#include ++ ++using std::bind; ++ ++#define slot1(name, method) \ ++ std::bind(&CSetupExtTools::slotSetPathXOverride, this, name, [](const QString& path){IAppSetup::self().method(path); }) ++ ++#define slot2(method) \ ++ std::bind(&CSetupExtTools::slotResetPathXOverride, this, [](){IAppSetup::self().method(); }) ++ ++CSetupExtTools::CSetupExtTools(QWidget *parent) ++ : QDialog(parent) ++{ ++ setupUi(this); ++ setupGui(); ++ ++ connect(toolPathGdaladdo, &QToolButton::pressed, this, slot1("gdaladdo", setGdaladdoOverride)); ++ connect(toolPathGdaltranslate, &QToolButton::pressed, this, slot1("gdal_translate", setGdaltranslateOverride)); ++ connect(toolPathGdalwarp, &QToolButton::pressed, this, slot1("gdalwarp", setGdalwarpOverride)); ++ connect(toolPathGdalbuildvrt, &QToolButton::pressed, this, slot1("gdalbuildvrt", setGdalbuildvrtOverride)); ++ connect(toolPathQmtrgb2pct, &QToolButton::pressed, this, slot1("qmt_rgb2pct", setQmtrgb2pctOverride)); ++ connect(toolPathQmtmap2jnx, &QToolButton::pressed, this, slot1("qmt_map2jnx", setQmtmap2jnxOverride)); ++ ++ connect(toolResetGdaladdo, &QToolButton::pressed, this, slot2(resetGdaladdoOverride)); ++ connect(toolResetGdaltranslate, &QToolButton::pressed, this, slot2(resetGdaltranslateOverride)); ++ connect(toolResetGdalwarp, &QToolButton::pressed, this, slot2(resetGdalwarpOverride)); ++ connect(toolResetGdalbuildvrt, &QToolButton::pressed, this, slot2(resetGdalbuildvrtOverride)); ++ connect(toolResetQmtrgb2pct, &QToolButton::pressed, this, slot2(resetQmtrgb2pctOverride)); ++ connect(toolResetQmtmap2jnx, &QToolButton::pressed, this, slot2(resetQmtmap2jnxOverride)); ++} ++ ++void CSetupExtTools::setupGui() ++{ ++ const IAppSetup& setup = IAppSetup::self(); ++ const QString& gdaladdo = setup.getGdaladdo(); ++ const QString& gdaltranslate = setup.getGdaltranslate(); ++ const QString& gdalwarp = setup.getGdalwarp(); ++ const QString& gdalbuildvrt = setup.getGdalbuildvrt(); ++ const QString& qmtrgb2pct = setup.getQmtrgb2pct(); ++ const QString& qmtmap2jnx = setup.getQmtmap2jnx(); ++ ++ labelPathGdaladdo->setText(gdaladdo.isEmpty() ? tr("not found") : gdaladdo); ++ labelPathGdaltranslate->setText(gdaltranslate.isEmpty() ? tr("not found") : gdaltranslate); ++ labelPathGdalwarp->setText(gdalwarp.isEmpty() ? tr("not found") : gdalwarp); ++ labelPathGdalbuildvrt->setText(gdalbuildvrt.isEmpty() ? tr("not found") : gdalbuildvrt); ++ labelPathQmtrgb2pct->setText(qmtrgb2pct.isEmpty() ? tr("not found") : qmtrgb2pct); ++ labelPathQmtmap2jnx->setText(qmtmap2jnx.isEmpty() ? tr("not found") : qmtmap2jnx); ++ ++ toolResetGdaladdo->setEnabled(setup.isGdaladdoOverride()); ++ toolResetGdaltranslate->setEnabled(setup.isGdaltranslateOverride()); ++ toolResetGdalwarp->setEnabled(setup.isGdalwarpOverride()); ++ toolResetGdalbuildvrt->setEnabled(setup.isGdalbuildvrtOverride()); ++ toolResetQmtrgb2pct->setEnabled(setup.isQmtrgb2pctOverride()); ++ toolResetQmtmap2jnx->setEnabled(setup.isQmtmap2jnxOverride()); ++} ++ ++void CSetupExtTools::slotSetPathXOverride(const QString& name, fSetPath setPath) ++{ ++ const QString& path = QFileDialog::getOpenFileName(this, tr("Select %1 binary...").arg(name), QDir::rootPath()); ++ if(path.isEmpty()) ++ { ++ return; ++ } ++ setPath(path); ++ setupGui(); ++} ++ ++void CSetupExtTools::slotResetPathXOverride(fResetPath resetPath) ++{ ++ resetPath(); ++ setupGui(); ++} +diff --git a/src/qmaptool/setup/CSetupExtTools.h b/src/qmaptool/setup/CSetupExtTools.h +new file mode 100644 +index 00000000..f93c264f +--- /dev/null ++++ b/src/qmaptool/setup/CSetupExtTools.h +@@ -0,0 +1,46 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CSETUPEXTTOOLS_H ++#define CSETUPEXTTOOLS_H ++ ++#include ++#include ++ ++#include "ui_ISetupExtTools.h" ++ ++using fResetPath = std::function; ++using fSetPath = std::function; ++ ++class CSetupExtTools : public QDialog, private Ui::ISetupExtTools ++{ ++ Q_OBJECT ++public: ++ CSetupExtTools(QWidget * parent); ++ virtual ~CSetupExtTools() = default; ++ ++private slots: ++ void slotSetPathXOverride(const QString& name, fSetPath setPath); ++ void slotResetPathXOverride(fResetPath resetPath); ++ ++private: ++ void setupGui(); ++}; ++ ++#endif //CSETUPEXTTOOLS_H ++ +diff --git a/src/qmaptool/setup/IAppSetup.cpp b/src/qmaptool/setup/IAppSetup.cpp +new file mode 100644 +index 00000000..912dc0ef +--- /dev/null ++++ b/src/qmaptool/setup/IAppSetup.cpp +@@ -0,0 +1,161 @@ ++/********************************************************************************************** ++ Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++ ++#include "setup/CCommandProcessor.h" ++#include "setup/CLogHandler.h" ++#include "setup/IAppSetup.h" ++ ++#include "setup/CAppSetupLinux.h" ++#include "setup/CAppSetupMac.h" ++#include "setup/CAppSetupWin.h" ++ ++#include "helpers/CSettings.h" ++ ++#include ++ ++ ++IAppSetup* IAppSetup::pSelf = nullptr; ++ ++IAppSetup& IAppSetup::self() ++{ ++ return *pSelf; ++} ++ ++IAppSetup::~IAppSetup() ++{ ++ SETTINGS; ++ cfg.setValue("ExtTools/pathGdaladdoOverride",pathGdaladdoOverride); ++ cfg.setValue("ExtTools/pathGdaltranslateOverride",pathGdaltranslateOverride); ++ cfg.setValue("ExtTools/pathGdalwarpOverride",pathGdalwarpOverride); ++ cfg.setValue("ExtTools/pathGdalbuildvrtOverride",pathGdalbuildvrtOverride); ++ cfg.setValue("ExtTools/pathQmtrgb2pctOverride",pathQmtrgb2pctOverride); ++ cfg.setValue("ExtTools/pathQmtmap2jnxOverride",pathQmtmap2jnxOverride); ++} ++ ++IAppSetup& IAppSetup::createInstance(QObject * parent) ++{ ++ if(pSelf != nullptr) ++ { ++ return self(); ++ } ++#if defined(Q_OS_MAC) ++ new CAppSetupMac(parent); ++#elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(__FreeBSD_kernel__) || defined(__GNU__) || defined(Q_OS_CYGWIN) ++ new CAppSetupLinux(parent); ++#elif defined (Q_OS_WIN32) ++ new CAppSetupWin(parent); ++#else ++ #error OS not supported ++#endif ++ return self(); ++} ++ ++void IAppSetup::prepareToolPaths() ++{ ++ pathGdaladdo = this->findExecutable("gdaladdo"); ++ pathGdaltranslate = this->findExecutable("gdal_translate"); ++ pathGdalwarp = this->findExecutable("gdalwarp"); ++ pathGdalbuildvrt = this->findExecutable("gdalbuildvrt"); ++ pathQmtrgb2pct = this->findExecutable("qmt_rgb2pct"); ++ pathQmtmap2jnx = this->findExecutable("qmt_map2jnx"); ++ ++ SETTINGS; ++ pathGdaladdoOverride = cfg.value("ExtTools/pathGdaladdoOverride",pathGdaladdoOverride).toString(); ++ pathGdaltranslateOverride = cfg.value("ExtTools/pathGdaltranslateOverride",pathGdaltranslateOverride).toString(); ++ pathGdalwarpOverride = cfg.value("ExtTools/pathGdalwarpOverride",pathGdalwarpOverride).toString(); ++ pathGdalbuildvrtOverride = cfg.value("ExtTools/pathGdalbuildvrtOverride", pathGdalbuildvrtOverride).toString(); ++ pathQmtrgb2pctOverride = cfg.value("ExtTools/pathQmtrgb2pctOverride", pathQmtrgb2pctOverride).toString(); ++ pathQmtmap2jnxOverride = cfg.value("ExtTools/pathQmtmap2jnxOverride", pathQmtmap2jnxOverride).toString(); ++} ++ ++void IAppSetup::prepareGdal(QString gdalDir, QString projDir) ++{ ++ if(!gdalDir.isEmpty()) ++ { ++ qputenv("GDAL_DATA", gdalDir.toUtf8()); ++ qDebug() << "GDAL_DATA directory set to " + gdalDir; ++ } ++ ++ if(!projDir.isEmpty()) ++ { ++ qputenv("PROJ_LIB", projDir.toUtf8()); ++ qDebug() << "PROJ_LIB directory set to " + projDir; ++ } ++ ++ GDALAllRegister(); ++} ++ ++ ++QString IAppSetup::path(QString path, QString subdir, bool mkdir, QString debugName) ++{ ++ QDir pathDir(path); ++ ++ if(subdir != 0) ++ { ++ pathDir = QDir(pathDir.absoluteFilePath(subdir)); ++ } ++ if(mkdir && !pathDir.exists()) ++ { ++ pathDir.mkpath(pathDir.absolutePath()); ++ qDebug() << debugName << "path created" << pathDir.absolutePath(); ++ } ++ else if (debugName != 0) ++ { ++ qDebug() << debugName << "path" << pathDir.absolutePath(); ++ } ++ return pathDir.absolutePath(); ++} ++ ++ ++void IAppSetup::prepareTranslator(QString translationPath, QString translationPrefix) ++{ ++ QString locale = QLocale::system().name(); ++ QDir dir(translationPath); ++ if(!QFile::exists(dir.absoluteFilePath(translationPrefix + locale))) ++ { ++ locale = locale.left(2); ++ } ++ qDebug() << "locale" << locale; ++ ++ QApplication* app = (QApplication*) QCoreApplication::instance(); ++ QTranslator *qtTranslator = new QTranslator(app); ++ if (qtTranslator->load(translationPrefix + locale, translationPath)) ++ { ++ app->installTranslator(qtTranslator); ++ qDebug() << "using file '"+ translationPath + "/" + translationPrefix + locale + ".qm' for translations."; ++ } ++ else ++ { ++ qWarning() << "no file found for translations '"+ translationPath + "/" + translationPrefix + locale + "' (using default)."; ++ } ++} ++ ++ ++void IAppSetup::initLogHandler() ++{ ++ CLogHandler::initLogHandler(logDir(), qlOpts->logfile, qlOpts->debug); ++} ++ ++CAppOpts *qlOpts = nullptr; ++ ++void IAppSetup::processArguments() ++{ ++ CCommandProcessor cmdParse; ++ qlOpts = cmdParse.processOptions(QCoreApplication::instance()->arguments()); ++} +diff --git a/src/qmaptool/setup/IAppSetup.h b/src/qmaptool/setup/IAppSetup.h +new file mode 100644 +index 00000000..6718332c +--- /dev/null ++++ b/src/qmaptool/setup/IAppSetup.h +@@ -0,0 +1,210 @@ ++/********************************************************************************************** ++ Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef IAPPSETUP_H ++#define IAPPSETUP_H ++ ++#include "CAppOpts.h" ++#include ++#include ++ ++ ++class IAppSetup : public QObject ++{ ++ Q_OBJECT ++public: ++ static IAppSetup& self(); ++ static IAppSetup &createInstance(QObject * parent); ++ ++ virtual ~IAppSetup(); ++ ++ virtual void initQMapTool() = 0; ++ void initLogHandler(); ++ void processArguments(); ++ ++ virtual QString defaultCachePath() = 0; ++ virtual QString userDataPath(QString subdir = 0) = 0; ++ virtual QString logDir() = 0; ++ virtual QString findExecutable(const QString &name) = 0; ++ ++ QString getGdaladdo() const ++ { ++ return QFile::exists(pathGdaladdoOverride) ? pathGdaladdoOverride : QFile::exists(pathGdaladdo) ? pathGdaladdo : ""; ++ } ++ ++ QString getGdaltranslate() const ++ { ++ return QFile::exists(pathGdaltranslateOverride) ? pathGdaltranslateOverride : QFile::exists(pathGdaltranslate) ? pathGdaltranslate : ""; ++ } ++ ++ QString getGdalwarp() const ++ { ++ return QFile::exists(pathGdalwarpOverride) ? pathGdalwarpOverride : QFile::exists(pathGdalwarp) ? pathGdalwarp : ""; ++ } ++ ++ QString getGdalbuildvrt() const ++ { ++ return QFile::exists(pathGdalbuildvrtOverride) ? pathGdalbuildvrtOverride : QFile::exists(pathGdalbuildvrt) ? pathGdalbuildvrt : ""; ++ } ++ ++ QString getQmtrgb2pct() const ++ { ++ return QFile::exists(pathQmtrgb2pctOverride) ? pathQmtrgb2pctOverride : QFile::exists(pathQmtrgb2pct) ? pathQmtrgb2pct : ""; ++ } ++ ++ QString getQmtmap2jnx() const ++ { ++ return QFile::exists(pathQmtmap2jnxOverride) ? pathQmtmap2jnxOverride : QFile::exists(pathQmtmap2jnx) ? pathQmtmap2jnx : ""; ++ } ++ ++ void setGdaladdoOverride(const QString& path) ++ { ++ pathGdaladdoOverride = path; ++ emit sigSetupChanged(); ++ } ++ ++ void setGdaltranslateOverride(const QString& path) ++ { ++ pathGdaltranslateOverride = path; ++ emit sigSetupChanged(); ++ } ++ ++ void setGdalwarpOverride(const QString& path) ++ { ++ pathGdalwarpOverride = path; ++ emit sigSetupChanged(); ++ } ++ ++ void setGdalbuildvrtOverride(const QString& path) ++ { ++ pathGdalbuildvrtOverride = path; ++ emit sigSetupChanged(); ++ } ++ ++ void setQmtrgb2pctOverride(const QString& path) ++ { ++ pathQmtrgb2pctOverride = path; ++ emit sigSetupChanged(); ++ } ++ ++ void setQmtmap2jnxOverride(const QString& path) ++ { ++ pathQmtmap2jnxOverride = path; ++ emit sigSetupChanged(); ++ } ++ ++ void resetGdaladdoOverride() ++ { ++ pathGdaladdoOverride.clear(); ++ emit sigSetupChanged(); ++ } ++ ++ void resetGdaltranslateOverride() ++ { ++ pathGdaltranslateOverride.clear(); ++ emit sigSetupChanged(); ++ } ++ ++ void resetGdalwarpOverride() ++ { ++ pathGdalwarpOverride.clear(); ++ emit sigSetupChanged(); ++ } ++ ++ void resetGdalbuildvrtOverride() ++ { ++ pathGdalbuildvrtOverride.clear(); ++ emit sigSetupChanged(); ++ } ++ ++ void resetQmtrgb2pctOverride() ++ { ++ pathQmtrgb2pctOverride.clear(); ++ emit sigSetupChanged(); ++ } ++ ++ void resetQmtmap2jnxOverride() ++ { ++ pathQmtmap2jnxOverride.clear(); ++ emit sigSetupChanged(); ++ } ++ ++ bool isGdaladdoOverride() const ++ { ++ return !pathGdaladdoOverride.isEmpty(); ++ } ++ ++ bool isGdaltranslateOverride() const ++ { ++ return !pathGdaltranslateOverride.isEmpty(); ++ } ++ ++ bool isGdalwarpOverride() const ++ { ++ return !pathGdalwarpOverride.isEmpty(); ++ } ++ ++ bool isGdalbuildvrtOverride() const ++ { ++ return !pathGdalbuildvrtOverride.isEmpty(); ++ } ++ ++ bool isQmtrgb2pctOverride() const ++ { ++ return !pathQmtrgb2pctOverride.isEmpty(); ++ } ++ ++ bool isQmtmap2jnxOverride() const ++ { ++ return !pathQmtmap2jnxOverride.isEmpty(); ++ } ++ ++signals: ++ void sigSetupChanged(); ++ ++protected: ++ static IAppSetup* pSelf; ++ ++ IAppSetup(QObject * parent) ++ : QObject(parent) ++ { ++ pSelf = this; ++ } ++ ++ void prepareGdal(QString gdalDir, QString projDir); ++ void prepareTranslator(QString translationPath, QString translationPrefix); ++ void prepareToolPaths(); ++ ++ QString path(QString path, QString subdir, bool mkdir, QString debugName); ++ ++ QString pathGdaladdo; ++ QString pathGdaltranslate; ++ QString pathGdalwarp; ++ QString pathGdalbuildvrt; ++ QString pathQmtrgb2pct; ++ QString pathQmtmap2jnx; ++ ++ QString pathGdaladdoOverride; ++ QString pathGdaltranslateOverride; ++ QString pathGdalwarpOverride; ++ QString pathGdalbuildvrtOverride; ++ QString pathQmtrgb2pctOverride; ++ QString pathQmtmap2jnxOverride; ++}; ++ ++#endif // IAPPSETUP_H +diff --git a/src/qmaptool/setup/ISetupExtTools.ui b/src/qmaptool/setup/ISetupExtTools.ui +new file mode 100644 +index 00000000..59a4db1e +--- /dev/null ++++ b/src/qmaptool/setup/ISetupExtTools.ui +@@ -0,0 +1,360 @@ ++ ++ ++ ISetupExtTools ++ ++ ++ ++ 0 ++ 0 ++ 400 ++ 348 ++ ++ ++ ++ Setup Ext. Tools ++ ++ ++ ++ ++ ++ ++ ++ <b style='color: red;'>not found</b> ++ ++ ++ ++ ++ ++ ++ Setup user defined path. ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/PathBlue.png:/icons/32x32/PathBlue.png ++ ++ ++ ++ ++ ++ ++ gdalbuildvrt ++ ++ ++ ++ ++ ++ ++ Reset user defined path setup. ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/Reset.png:/icons/32x32/Reset.png ++ ++ ++ ++ ++ ++ ++ <b style='color: red;'>not found</b> ++ ++ ++ ++ ++ ++ ++ Reset user defined path setup. ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/Reset.png:/icons/32x32/Reset.png ++ ++ ++ ++ ++ ++ ++ Reset user defined path setup. ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/Reset.png:/icons/32x32/Reset.png ++ ++ ++ ++ ++ ++ ++ <b style='color: red;'>not found</b> ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ gdal_translate: ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ gdalwarp: ++ ++ ++ ++ ++ ++ ++ Setup user defined path. ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/PathBlue.png:/icons/32x32/PathBlue.png ++ ++ ++ ++ ++ ++ ++ Reset user defined path setup. ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/Reset.png:/icons/32x32/Reset.png ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ gdaladdo: ++ ++ ++ ++ ++ ++ ++ <b style='color: red;'>not found</b> ++ ++ ++ ++ ++ ++ ++ Setup user defined path. ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/PathBlue.png:/icons/32x32/PathBlue.png ++ ++ ++ ++ ++ ++ ++ <b style='color: red;'>not found</b> ++ ++ ++ ++ ++ ++ ++ qmt_rgb2pct ++ ++ ++ ++ ++ ++ ++ Setup user defined path. ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/PathBlue.png:/icons/32x32/PathBlue.png ++ ++ ++ ++ ++ ++ ++ Setup user defined path. ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/PathBlue.png:/icons/32x32/PathBlue.png ++ ++ ++ ++ ++ ++ ++ Reset user defined path setup. ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/Reset.png:/icons/32x32/Reset.png ++ ++ ++ ++ ++ ++ ++ qmt_map2jnx ++ ++ ++ ++ ++ ++ ++ <b style='color: red;'>not found</b> ++ ++ ++ ++ ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/PathBlue.png:/icons/32x32/PathBlue.png ++ ++ ++ ++ ++ ++ ++ ... ++ ++ ++ ++ :/icons/32x32/Reset.png:/icons/32x32/Reset.png ++ ++ ++ ++ ++ ++ ++ ++ ++ <b>Note:</b> Usually QMapTool should detect all external tools by itself. If it does not, it's a bad setup and you should fix the PATH variable of your system. You can setup the paths manually, too, if you know what you are doing. But please keep in mind that GDAL needs a proper environment setup to function properly. If it's not setup properly you might get results but these can be off grid. ++ ++ ++ Qt::AlignJustify|Qt::AlignVCenter ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ Qt::Vertical ++ ++ ++ ++ 20 ++ 40 ++ ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ QDialogButtonBox::Ok ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ buttonBox ++ accepted() ++ ISetupExtTools ++ accept() ++ ++ ++ 248 ++ 254 ++ ++ ++ 157 ++ 274 ++ ++ ++ ++ ++ buttonBox ++ rejected() ++ ISetupExtTools ++ reject() ++ ++ ++ 316 ++ 260 ++ ++ ++ 286 ++ 274 ++ ++ ++ ++ ++ +diff --git a/src/qmaptool/shell/CShell.cpp b/src/qmaptool/shell/CShell.cpp +new file mode 100644 +index 00000000..e124adba +--- /dev/null ++++ b/src/qmaptool/shell/CShell.cpp +@@ -0,0 +1,198 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "CMainWindow.h" ++#include "shell/CShell.h" ++ ++#include ++ ++CShell * CShell::pSelf = nullptr; ++ ++CShell::CShell(QWidget *parent) ++ : QTextBrowser(parent) ++{ ++ pSelf = this; ++ ++ connect(&cmd, &QProcess::readyReadStandardError, this, &CShell::slotStderr); ++ connect(&cmd, &QProcess::readyReadStandardOutput, this, &CShell::slotStdout); ++ ++ connect(&cmd, static_cast(&QProcess::finished), this, &CShell::slotFinished); ++ connect(&cmd, static_cast(&QProcess::error), this, &CShell::slotError); ++} ++ ++void CShell::slotError(QProcess::ProcessError error) ++{ ++ setTextColor(Qt::red); ++ insertPlainText(QString(tr("Execution of external program `%1` failed: ")).arg(cmd.program())); ++ switch(error) ++ { ++ case QProcess::FailedToStart: ++ insertPlainText(QString(tr("Process cannot be started.\n"))); ++ insertPlainText(QString(tr("Make sure the required packages are installed, `%1` exists and is executable.\n")).arg(cmd.program())); ++ break; ++ ++ case QProcess::Crashed: ++ insertPlainText(QString(tr("External process crashed.\n"))); ++ break; ++ ++ default: ++ insertPlainText(QString(tr("An unknown error occurred.\n"))); ++ break; ++ } ++} ++ ++void CShell::slotStderr() ++{ ++ QString str; ++ setTextColor(Qt::red); ++ str = cmd.readAllStandardError(); ++ ++ if(str[0] == '\r') ++ { ++#ifdef WIN32 ++ if(str.contains("\n")) ++ { ++ insertPlainText("\n"); ++ } ++ else ++#endif // WIN32 ++ { ++ moveCursor( QTextCursor::End, QTextCursor::MoveAnchor ); ++ moveCursor( QTextCursor::StartOfLine, QTextCursor::MoveAnchor ); ++ moveCursor( QTextCursor::End, QTextCursor::KeepAnchor ); ++ textCursor().removeSelectedText(); ++ } ++ ++ ++#ifdef WIN32 ++ str = str.split("\r").last().remove("\r").remove("\n"); ++#else ++ str = str.split("\r").last(); ++#endif ++ } ++ ++ insertPlainText(str); ++ verticalScrollBar()->setValue(verticalScrollBar()->maximum()); ++} ++ ++void CShell::slotStdout() ++{ ++ QString str; ++ setTextColor(Qt::blue); ++ str = cmd.readAllStandardOutput(); ++ ++ if(str[0] == '\r') ++ { ++#ifdef WIN32 ++ if(str.contains("\n")) ++ { ++ insertPlainText("\n"); ++ } ++ else ++#endif // WIN32 ++ { ++ moveCursor( QTextCursor::End, QTextCursor::MoveAnchor ); ++ moveCursor( QTextCursor::StartOfLine, QTextCursor::MoveAnchor ); ++ moveCursor( QTextCursor::End, QTextCursor::KeepAnchor ); ++ textCursor().removeSelectedText(); ++ } ++ ++#ifdef WIN32 ++ str = str.split("\r").last().remove("\r").remove("\n"); ++#else ++ str = str.split("\r").last(); ++#endif ++ } ++ ++ insertPlainText(str); ++ verticalScrollBar()->setValue(verticalScrollBar()->maximum()); ++} ++ ++void CShell::stdOut(const QString& str) ++{ ++ setTextColor(Qt::black); ++ append(str); ++} ++ ++ ++void CShell::stdErr(const QString& str) ++{ ++ setTextColor(Qt::red); ++ append(str); ++} ++ ++ ++void CShell::slotFinished(int exitCode, QProcess::ExitStatus status) ++{ ++ if(exitCode || status) ++ { ++ emit sigFinishedJob(jobId); ++ setTextColor(Qt::red); ++ append(tr("!!! failed !!!\n")); ++ return; ++ } ++ ++ ++idxCommand; ++ nextCommand(); ++} ++ ++void CShell::slotCancel() ++{ ++ if(cmd.state() == QProcess::NotRunning) ++ { ++ return; ++ } ++ ++ stdOut(tr("\nCanceled by user's request.\n")); ++ cmd.kill(); ++ cmd.waitForFinished(10000); ++} ++ ++int CShell::execute(QList cmds) ++{ ++ CMainWindow::self().makeShellVisible(); ++ ++ if(cmd.state() != QProcess::NotRunning) ++ { ++ return -1; ++ } ++ ++ clear(); ++ ++ idxCommand = 0; ++ commands = cmds; ++ ++ nextCommand(); ++ return ++jobId; ++} ++ ++ ++void CShell::nextCommand() ++{ ++ if(idxCommand >= commands.size()) ++ { ++ emit sigFinishedJob(jobId); ++ setTextColor(Qt::darkGreen); ++ append(tr("!!! done !!!\n")); ++ return; ++ } ++ ++ const CShellCmd& command = commands[idxCommand]; ++ stdOut(command.getCmd() + " " + command.getArgs().join(" ") + "\n"); ++ cmd.start(command.getCmd(), command.getArgs()); ++} +diff --git a/src/qmaptool/shell/CShell.h b/src/qmaptool/shell/CShell.h +new file mode 100644 +index 00000000..b4330c78 +--- /dev/null ++++ b/src/qmaptool/shell/CShell.h +@@ -0,0 +1,75 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CSHELL_H ++#define CSHELL_H ++ ++#include "shell/CShellCmd.h" ++ ++#include ++#include ++#include ++ ++class CShell : public QTextBrowser ++{ ++ Q_OBJECT ++public: ++ static CShell& self() ++ { ++ return *pSelf; ++ } ++ ++ virtual ~CShell() = default; ++ ++ int execute(QList cmds); ++signals: ++ void sigFinishedJob(qint32 jobId); ++ ++public slots: ++ void slotCancel(); ++ ++protected slots: ++ /// read the stderr from the process and paste it into the text browser ++ void slotStderr(); ++ /// read the stdout from the process and paste it into the text browser ++ void slotStdout(); ++ void slotError(QProcess::ProcessError error); ++ virtual void slotFinished(int exitCode, QProcess::ExitStatus status); ++ ++protected: ++ void nextCommand(); ++ ++ /// write text to stdout color channel of the text browser ++ void stdOut(const QString& str); ++ /// write text to stderr color channel of the text browser ++ void stdErr(const QString& str); ++ ++ QProcess cmd; ++ ++ QList commands; ++ qint32 idxCommand = 0; ++ qint32 jobId = 0; ++ ++private: ++ friend class Ui_IMainWindow; ++ CShell(QWidget * parent); ++ static CShell * pSelf; ++}; ++ ++#endif //CSHELL_H ++ +diff --git a/src/qmaptool/shell/CShellCmd.cpp b/src/qmaptool/shell/CShellCmd.cpp +new file mode 100644 +index 00000000..25980d7c +--- /dev/null ++++ b/src/qmaptool/shell/CShellCmd.cpp +@@ -0,0 +1,27 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "shell/CShellCmd.h" ++ ++CShellCmd::CShellCmd(const QString &cmd, const QStringList &args) ++ : cmd(cmd) ++ , args(args) ++{ ++} ++ ++ +diff --git a/src/qmaptool/shell/CShellCmd.h b/src/qmaptool/shell/CShellCmd.h +new file mode 100644 +index 00000000..f440325e +--- /dev/null ++++ b/src/qmaptool/shell/CShellCmd.h +@@ -0,0 +1,47 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CSHELLCMD_H ++#define CSHELLCMD_H ++ ++#include ++#include ++ ++class CShellCmd ++{ ++public: ++ CShellCmd(const QString& cmd, const QStringList& args); ++ virtual ~CShellCmd() = default; ++ ++ const QString& getCmd() const ++ { ++ return cmd; ++ } ++ ++ const QStringList& getArgs() const ++ { ++ return args; ++ } ++ ++private: ++ QString cmd; ++ QStringList args; ++}; ++ ++#endif //CSHELLCMD_H ++ +diff --git a/src/qmaptool/tool/CToolAddOverview.cpp b/src/qmaptool/tool/CToolAddOverview.cpp +new file mode 100644 +index 00000000..88b8b712 +--- /dev/null ++++ b/src/qmaptool/tool/CToolAddOverview.cpp +@@ -0,0 +1,225 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "canvas/IDrawContext.h" ++#include "CMainWindow.h" ++#include "helpers/CSettings.h" ++#include "items/CItemFile.h" ++#include "setup/IAppSetup.h" ++#include "tool/CToolAddOverview.h" ++ ++CToolAddOverview::CToolAddOverview(QWidget *parent) ++ : IToolGui(parent) ++{ ++ setupUi(this); ++ setObjectName(tr("Add Overviews")); ++ ++ labelHelp->setText(tr("Raster map files consume quite some memory if a larger area is displayed. " ++ "Pre-calculated overview levels help to speed up loading and displaying the " ++ "map. These overviews can be stored within the map file as well as an external " ++ "file. GDAL can remove internally stored overviews, however it will not free " ++ "the used space in the file. Therefore it's size will remain large. If you " ++ "do not like that use the external option.")); ++ ++ labelHelp->setVisible(CMainWindow::self().showToolHelp()->isChecked()); ++ connect(CMainWindow::self().showToolHelp(), &QAction::toggled, labelHelp, &QLabel::setVisible); ++ ++ connect(itemList, &CItemListWidget::sigAddItem, this, &CToolAddOverview::slotAddItem); ++ connect(checkBy2, &QCheckBox::stateChanged, this, &CToolAddOverview::slotSelectionChanged); ++ connect(checkBy4, &QCheckBox::stateChanged, this, &CToolAddOverview::slotSelectionChanged); ++ connect(checkBy8, &QCheckBox::stateChanged, this, &CToolAddOverview::slotSelectionChanged); ++ connect(checkBy16, &QCheckBox::stateChanged, this, &CToolAddOverview::slotSelectionChanged); ++ connect(checkBy32, &QCheckBox::stateChanged, this, &CToolAddOverview::slotSelectionChanged); ++ connect(checkBy64, &QCheckBox::stateChanged, this, &CToolAddOverview::slotSelectionChanged); ++ connect(checkRemove, &QCheckBox::stateChanged, this, &CToolAddOverview::slotSelectionChanged); ++ ++ connect(itemList, &CItemListWidget::sigSelectionChanged, this, &CToolAddOverview::slotMapSelectionChanged); ++ ++ connect(pushStart, &QPushButton::clicked, this, &CToolAddOverview::slotStart); ++ connect(pushCancel, &QPushButton::clicked, &CShell::self(), &CShell::slotCancel); ++ connect(&CShell::self(), &CShell::sigFinishedJob, this, &CToolAddOverview::slotFinished); ++ ++ ++ setupChanged(); ++ ++ SETTINGS; ++ cfg.beginGroup("ToolAddOverview"); ++ itemList->loadSettings(cfg); ++ checkBy2->setChecked(cfg.value("by2", false).toBool()); ++ checkBy4->setChecked(cfg.value("by4", false).toBool()); ++ checkBy8->setChecked(cfg.value("by8", false).toBool()); ++ checkBy16->setChecked(cfg.value("by16", false).toBool()); ++ checkBy32->setChecked(cfg.value("by32", false).toBool()); ++ checkBy64->setChecked(cfg.value("by64", false).toBool()); ++ checkExternal->setChecked(cfg.value("useExternal", true).toBool()); ++ checkAllFiles->setChecked(cfg.value("allFiles", false).toBool()); ++ cfg.endGroup(); ++} ++ ++CToolAddOverview::~CToolAddOverview() ++{ ++ SETTINGS; ++ cfg.beginGroup("ToolAddOverview"); ++ cfg.remove(""); ++ itemList->saveSettings(cfg); ++ cfg.setValue("by2", checkBy2->isChecked()); ++ cfg.setValue("by4", checkBy4->isChecked()); ++ cfg.setValue("by8", checkBy8->isChecked()); ++ cfg.setValue("by16", checkBy16->isChecked()); ++ cfg.setValue("by32", checkBy32->isChecked()); ++ cfg.setValue("by64", checkBy64->isChecked()); ++ cfg.setValue("useExternal", checkExternal->isChecked()); ++ cfg.setValue("allFiles", checkAllFiles->isChecked()); ++ cfg.endGroup(); ++} ++ ++ ++void CToolAddOverview::setupChanged() ++{ ++ bool hasGdaladdo = !IAppSetup::self().getGdaladdo().isEmpty(); ++ labelNoGdaladdo->setVisible(!hasGdaladdo); ++ frame->setVisible(hasGdaladdo); ++} ++ ++void CToolAddOverview::slotAddItem(const QString& filename, QListWidget * list) ++{ ++ CItemFile * item = new CItemFile(filename, list); ++ connect(item, &CItemFile::sigChanged, itemList, &CItemListWidget::sigChanged); ++} ++ ++void CToolAddOverview::slotMapSelectionChanged() ++{ ++ CMainWindow::self().getCanvas()->slotTriggerCompleteUpdate(CCanvas::eRedrawAll); ++ slotSelectionChanged(); ++} ++ ++void CToolAddOverview::slotSelectionChanged() ++{ ++ bool enable = checkBy2->isChecked()|checkBy4->isChecked()|checkBy8->isChecked()|checkBy16->isChecked()|checkBy32->isChecked()|checkBy64->isChecked()|checkRemove->isChecked(); ++ pushStart->setEnabled(enable && itemList->count()); ++ ++ bool isRemove = checkRemove->isChecked(); ++ frameLevels->setDisabled(isRemove); ++ checkExternal->setDisabled(isRemove); ++} ++ ++void CToolAddOverview::buildCmd(QList& cmds, const IItem *iitem) ++{ ++ const CItemFile * item = dynamic_cast(iitem); ++ if(nullptr == item) ++ { ++ return; ++ } ++ ++ item->getDrawContext()->unload(); ++ ++ // remove previous overview ++ QStringList args; ++ if(checkRemove->isChecked()) ++ { ++ args << "-clean" << item->getFilename(); ++ cmds << CShellCmd(IAppSetup::self().getGdaladdo(), args); ++ /// @todo: shrink the file ++ } ++ else ++ { ++ IDrawContext * context = item->getDrawContext(); ++ ++ // add new ones ++ args.clear(); ++ args << "-r"; ++ args << (context->is32BitRgb() ? "cubic" : "nearest"); ++ ++ if(checkExternal->isChecked()) ++ { ++ args << "-ro"; ++ } ++ ++ args << item->getFilename(); ++ if(checkBy2->isChecked()) ++ { ++ args << "2"; ++ } ++ if(checkBy4->isChecked()) ++ { ++ args << "4"; ++ } ++ if(checkBy8->isChecked()) ++ { ++ args << "8"; ++ } ++ if(checkBy16->isChecked()) ++ { ++ args << "16"; ++ } ++ if(checkBy32->isChecked()) ++ { ++ args << "32"; ++ } ++ if(checkBy64->isChecked()) ++ { ++ args << "64"; ++ } ++ ++ cmds << CShellCmd(IAppSetup::self().getGdaladdo(), args); ++ } ++} ++ ++void CToolAddOverview::slotStart() ++{ ++ start(itemList, checkAllFiles->isChecked()); ++ if(jobId > 0) ++ { ++ itemList->setEnabled(false); ++ frameInput->setEnabled(false); ++ pushStart->setEnabled(false); ++ pushCancel->setEnabled(true); ++ } ++} ++ ++void CToolAddOverview::slotFinished(qint32 id) ++{ ++ if(finished(id)) ++ { ++ itemList->setEnabled(true); ++ frameInput->setEnabled(true); ++ pushStart->setEnabled(true); ++ pushCancel->setEnabled(false); ++ } ++ ++ if(checkAllFiles->isChecked()) ++ { ++ const int N = itemList->count(); ++ for(int n = 0; n < N; n++) ++ { ++ IItem * item = itemList->item(n); ++ if(nullptr != item) ++ { ++ item->reload(); ++ } ++ } ++ } ++ else ++ { ++ IItem * item = itemList->currentItem(); ++ if(nullptr != item) ++ { ++ item->reload(); ++ } ++ } ++} +diff --git a/src/qmaptool/tool/CToolAddOverview.h b/src/qmaptool/tool/CToolAddOverview.h +new file mode 100644 +index 00000000..902c64aa +--- /dev/null ++++ b/src/qmaptool/tool/CToolAddOverview.h +@@ -0,0 +1,51 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CTOOLADDOVERVIEW_H ++#define CTOOLADDOVERVIEW_H ++ ++#include "items/IItem.h" ++#include "tool/ITool.h" ++#include "tool/IToolGui.h" ++#include "ui_IToolAddOverview.h" ++ ++ ++class CToolAddOverview : public IToolGui, public ITool, private Ui::IToolAddOverview ++{ ++ Q_OBJECT ++public: ++ CToolAddOverview(QWidget * parent); ++ virtual ~CToolAddOverview(); ++ ++ void setupChanged() override; ++ ++ FORWARD_LIST_ALL(itemList) ++ ++private slots: ++ void slotAddItem(const QString& filename, QListWidget * list); ++ void slotMapSelectionChanged(); ++ void slotSelectionChanged(); ++ void slotStart(); ++ void slotFinished(qint32 id); ++ ++protected: ++ void buildCmd(QList& cmds, const IItem * iitem) override; ++}; ++ ++#endif //CTOOLADDOVERVIEW_H ++ +diff --git a/src/qmaptool/tool/CToolBox.cpp b/src/qmaptool/tool/CToolBox.cpp +new file mode 100644 +index 00000000..c154280a +--- /dev/null ++++ b/src/qmaptool/tool/CToolBox.cpp +@@ -0,0 +1,44 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "CMainWindow.h" ++#include "tool/CToolBox.h" ++ ++CToolBox::CToolBox(QWidget *parent) ++ : QToolBox(parent) ++{ ++ connect(this, &CToolBox::currentChanged, this, &CToolBox::slotToolChanged); ++} ++ ++void CToolBox::setupChanged() ++{ ++ const int N = count(); ++ for(int n = 0; n < N; n++) ++ { ++ ITool * tool = dynamic_cast(widget(n)); ++ if(nullptr != tool) ++ { ++ tool->setupChanged(); ++ } ++ } ++} ++ ++void CToolBox::slotToolChanged(int idx) ++{ ++ CMainWindow::self().getCanvas()->slotTriggerCompleteUpdate(CCanvas::eRedrawAll); ++} +diff --git a/src/qmaptool/tool/CToolBox.h b/src/qmaptool/tool/CToolBox.h +new file mode 100644 +index 00000000..d357d903 +--- /dev/null ++++ b/src/qmaptool/tool/CToolBox.h +@@ -0,0 +1,40 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CTOOLBOX_H ++#define CTOOLBOX_H ++ ++#include "tool/ITool.h" ++#include ++ ++class CToolBox : public ITool, public QToolBox ++{ ++public: ++ CToolBox(QWidget * parent); ++ virtual ~CToolBox() = default; ++ ++ void setupChanged() override; ++ ++ FORWARD_WIDGET_ALL() ++ ++private slots: ++ void slotToolChanged(int idx); ++}; ++ ++#endif //CTOOLBOX_H ++ +diff --git a/src/qmaptool/tool/CToolCutMap.cpp b/src/qmaptool/tool/CToolCutMap.cpp +new file mode 100644 +index 00000000..a835230d +--- /dev/null ++++ b/src/qmaptool/tool/CToolCutMap.cpp +@@ -0,0 +1,202 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "canvas/IDrawContext.h" ++#include "CMainWindow.h" ++#include "helpers/CSettings.h" ++#include "items/CItemCutMap.h" ++#include "setup/IAppSetup.h" ++#include "tool/CToolCutMap.h" ++ ++CToolCutMap::CToolCutMap(QWidget *parent) ++ : IToolGui(parent) ++{ ++ setupUi(this); ++ setObjectName(tr("Cut Map")); ++ ++ labelHelp->setText(tr("Paper maps usually have a border you don't want to have. To combine " ++ "maps seamlessly you have to cut that border, replacing it by transparent " ++ "pixel. This tool allows you to define a cut line and it will add an alpha " ++ "channel for transparency to your map.")); ++ ++ labelHelp->setVisible(CMainWindow::self().showToolHelp()->isChecked()); ++ connect(CMainWindow::self().showToolHelp(), &QAction::toggled, labelHelp, &QLabel::setVisible); ++ ++ connect(itemList, &CItemListWidget::sigAddItem, this, &CToolCutMap::slotAddItem); ++ connect(itemList, &CItemListWidget::sigSelectionChanged, this, &CToolCutMap::slotMapSelectionChanged); ++ connect(itemList, &CItemListWidget::sigChanged, this, &CToolCutMap::slotSomethingChanged); ++ ++ connect(lineSuffix, &QLineEdit::textChanged, this, &CToolCutMap::slotSomethingChanged); ++ ++ connect(pushStart, &QPushButton::clicked, this, &CToolCutMap::slotStart); ++ connect(pushCancel, &QPushButton::clicked, &CShell::self(), &CShell::slotCancel); ++ connect(&CShell::self(), &CShell::sigFinishedJob, this, &CToolCutMap::slotFinished); ++ ++ setupChanged(); ++ ++ SETTINGS; ++ cfg.beginGroup("ToolCutMap"); ++ itemList->loadSettings(cfg); ++ groupOverviews->loadSettings(cfg); ++ checkAllFiles->setChecked(cfg.value("allFiles", false).toBool()); ++ lineSuffix->setText(cfg.value("suffix","_cut").toString()); ++ cfg.endGroup(); ++ ++ slotSomethingChanged(); ++} ++ ++CToolCutMap::~CToolCutMap() ++{ ++ SETTINGS; ++ cfg.beginGroup("ToolCutMap"); ++ cfg.remove(""); ++ itemList->saveSettings(cfg); ++ groupOverviews->saveSettings(cfg); ++ cfg.setValue("allFiles", checkAllFiles->isChecked()); ++ cfg.setValue("suffix", lineSuffix->text()); ++ cfg.endGroup(); ++} ++ ++void CToolCutMap::setupChanged() ++{ ++ bool hasGdalwarp = !IAppSetup::self().getGdalwarp().isEmpty(); ++ labelNoGdalwarp->setVisible(!hasGdalwarp); ++ ++ bool hasGdaladdo = !IAppSetup::self().getGdaladdo().isEmpty(); ++ labelNoGdaladdo->setVisible(!hasGdaladdo); ++ ++ frame->setVisible(hasGdalwarp && hasGdaladdo); ++} ++ ++void CToolCutMap::slotAddItem(const QString& filename, QListWidget * list) ++{ ++ CItemCutMap * item = new CItemCutMap(filename, stackedWidget, list); ++ connect(item, &CItemFile::sigChanged, itemList, &CItemListWidget::sigChanged); ++} ++ ++void CToolCutMap::slotMapSelectionChanged() ++{ ++ CMainWindow::self().getCanvas()->slotTriggerCompleteUpdate(CCanvas::eRedrawAll); ++ slotSomethingChanged(); ++} ++ ++void CToolCutMap::slotSomethingChanged() ++{ ++ IItem * item = itemList->currentItem(); ++ if(item != nullptr) ++ { ++ bool ok = item->isOk(); ++ if(lineSuffix->text().isEmpty()) ++ { ++ ok = false; ++ } ++ pushStart->setEnabled(ok); ++ } ++ else ++ { ++ pushStart->setEnabled(false); ++ } ++} ++ ++ ++void CToolCutMap::buildCmd(QList& cmds, const IItem *iitem) ++{ ++ const CItemCutMap * item = dynamic_cast(iitem); ++ if(nullptr == item) ++ { ++ return; ++ } ++ ++ // ---- command 1 ---------------------- ++ const IDrawContext * context = item->getDrawContext(); ++ QStringList args; ++ // --- overwrite last output file --- ++ args << "-overwrite"; ++ // --- use all CPU cores when possible --- ++ args << "-multi"; ++ args << "-wo"; ++ args << "NUM_THREADS=ALL_CPUS"; ++ ++ if(context->getProjection().isEmpty()) ++ { ++ // --- if the source in not referenced --- ++ args << "-to"; ++ args << "SRC_METHOD=NO_GEOTRANSFORM"; ++ args << "-to"; ++ args << "DST_METHOD=NO_GEOTRANSFORM"; ++ } ++ else ++ { ++ // --- this only works for referenced sources --- ++ args << "-crop_to_cutline"; ++ } ++ ++ // --- define transparent color --- ++ if(context->getRasterBandCount() == 1) ++ { ++ if(!context->getNoData()) ++ { ++ // --- use no data value for destination, too --- ++ args << "-dstnodata" << "255"; ++ } ++ } ++ else if(context->getRasterBandCount() == 3) ++ { ++ // --- add alpha channel to files with just RGB --- ++ args << "-dstalpha"; ++ } ++ ++ QString wktFilename = createTempFile("csv"); ++ item->saveShape(wktFilename); ++ QString inFilename = item->getFilename(); ++ QFileInfo fi(inFilename); ++ QString outFilename = fi.absoluteDir().absoluteFilePath(fi.completeBaseName() + lineSuffix->text() + "." + fi.suffix()); ++ ++ args << "-cutline"; ++ args << wktFilename; ++ args << inFilename; ++ args << outFilename; ++ ++ cmds << CShellCmd(IAppSetup::self().getGdalwarp(), args); ++ ++ // ---- command 2 ---------------------- ++ groupOverviews->buildCmd(cmds, outFilename, context->is32BitRgb() ? "cubic" : "nearest"); ++} ++ ++void CToolCutMap::slotStart() ++{ ++ start(itemList, checkAllFiles->isChecked()); ++ if(jobId > 0) ++ { ++ itemList->setEnabled(false); ++ frameInput->setEnabled(false); ++ pushStart->setEnabled(false); ++ pushCancel->setEnabled(true); ++ } ++} ++ ++void CToolCutMap::slotFinished(qint32 id) ++{ ++ if(finished(id)) ++ { ++ itemList->setEnabled(true); ++ frameInput->setEnabled(true); ++ pushStart->setEnabled(true); ++ pushCancel->setEnabled(false); ++ } ++} +diff --git a/src/qmaptool/tool/CToolCutMap.h b/src/qmaptool/tool/CToolCutMap.h +new file mode 100644 +index 00000000..c2f94938 +--- /dev/null ++++ b/src/qmaptool/tool/CToolCutMap.h +@@ -0,0 +1,51 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CTOOLCUTMAP_H ++#define CTOOLCUTMAP_H ++ ++#include "items/IItem.h" ++#include "tool/ITool.h" ++#include "tool/IToolGui.h" ++#include "ui_IToolCutMap.h" ++ ++class CToolCutMap : public IToolGui, public ITool, private Ui::IToolCutMap ++{ ++ Q_OBJECT ++public: ++ CToolCutMap(QWidget * parent); ++ virtual ~CToolCutMap(); ++ ++ void setupChanged() override; ++ ++ FORWARD_LIST_ALL(itemList) ++ ++ ++private slots: ++ void slotAddItem(const QString& filename, QListWidget * list); ++ void slotMapSelectionChanged(); ++ void slotSomethingChanged(); ++ void slotStart(); ++ void slotFinished(qint32 id); ++ ++private: ++ void buildCmd(QList& cmds, const IItem *iitem) override; ++}; ++ ++#endif //CTOOLCUTMAP_H ++ +diff --git a/src/qmaptool/tool/CToolExport.cpp b/src/qmaptool/tool/CToolExport.cpp +new file mode 100644 +index 00000000..41ae83f5 +--- /dev/null ++++ b/src/qmaptool/tool/CToolExport.cpp +@@ -0,0 +1,193 @@ ++/********************************************************************************************** ++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "CMainWindow.h" ++#include "helpers/CSettings.h" ++#include "items/CItemMap.h" ++#include "tool/CToolExport.h" ++ ++#include ++ ++CToolExport::CToolExport(QWidget *parent) ++ : IToolGui(parent) ++{ ++ setupUi(this); ++ setObjectName(tr("Export Maps")); ++ lineTragetFile->addAction(actionTargetFilename,QLineEdit::TrailingPosition); ++ ++ labelHelp->setText(tr("To use the maps on your device you have to export them to the proprietary " ++ "format supported by the device. Depending on the device this can vary from " ++ "a single layer map to a map stack with maps of different scale." ++ )); ++ ++ labelHelp->setVisible(CMainWindow::self().showToolHelp()->isChecked()); ++ connect(CMainWindow::self().showToolHelp(), &QAction::toggled, labelHelp, &QLabel::setVisible); ++ ++ labelNote->setText(tr("Note: This tool will use all files in the list as a input. " ++ "This will only work if all files have the same projection." ++ )); ++ labelNote->setVisible(CMainWindow::self().showToolHelp()->isChecked()); ++ connect(CMainWindow::self().showToolHelp(), &QAction::toggled, labelNote, &QLabel::setVisible); ++ ++ connect(itemTree, &CItemTreeWidget::sigSelectionChanged, this, &CToolExport::slotMapSelectionChanged); ++ connect(itemTree, &CItemTreeWidget::sigChanged, this, &CToolExport::slotSomethingChanged); ++ connect(lineTragetFile, &QLineEdit::textChanged, this, &CToolExport::slotSomethingChanged); ++ connect(actionTargetFilename, &QAction::triggered, this, &CToolExport::slotSelectFilename); ++ connect(comboExport, static_cast(&QComboBox::currentIndexChanged), stackedWidget, &QStackedWidget::setCurrentIndex); ++ ++ connect(pushStart, &QPushButton::clicked, this, &CToolExport::slotStart); ++ connect(pushCancel, &QPushButton::clicked, &CShell::self(), &CShell::slotCancel); ++ connect(&CShell::self(), &CShell::sigFinishedJob, this, &CToolExport::slotFinished); ++ ++ ++ setupChanged(); ++ ++ SETTINGS; ++ cfg.beginGroup("ToolExport"); ++ itemTree->loadSettings(cfg); ++ ++ comboExport->setCurrentIndex(cfg.value("current",0).toInt()); ++ lineTragetFile->setText(cfg.value("targetFile", "").toString()); ++ cfg.endGroup(); ++} ++ ++CToolExport::~CToolExport() ++{ ++ SETTINGS; ++ cfg.beginGroup("ToolExport"); ++ cfg.remove(""); ++ itemTree->saveSettings(cfg); ++ cfg.setValue("current", comboExport->currentIndex()); ++ cfg.setValue("targetFile", lineTragetFile->text()); ++ cfg.endGroup(); ++} ++ ++ ++void CToolExport::setupChanged() ++{ ++ bool hasMap2jnx = !IAppSetup::self().getQmtmap2jnx().isEmpty(); ++ labelNoMap2jnx->setVisible(!hasMap2jnx); ++ ++ frame->setVisible(hasMap2jnx); ++} ++ ++void CToolExport::slotMapSelectionChanged() ++{ ++ CMainWindow::self().getCanvas()->slotTriggerCompleteUpdate(CCanvas::eRedrawAll); ++ slotSomethingChanged(); ++} ++ ++ ++void CToolExport::slotSomethingChanged() ++{ ++ bool ok = true; ++ if(itemTree->topLevelItemCount() == 0) ++ { ++ ok = false; ++ } ++ if(lineTragetFile->text().isEmpty()) ++ { ++ ok = false; ++ } ++ pushStart->setEnabled(ok); ++} ++ ++void CToolExport::slotSelectFilename() ++{ ++ SETTINGS; ++ QString path = cfg.value("Path/mapInput", QDir::homePath()).toString(); ++ QString filename = QFileDialog::getSaveFileName(this, tr("Select filename..."), path); ++ if(filename.isEmpty()) ++ { ++ return; ++ } ++ cfg.setValue("Path/mapInput", QFileInfo(filename).absolutePath()); ++ ++ lineTragetFile->setText(filename); ++} ++ ++ ++void CToolExport::buildCmd(QList& cmds, const IItem * iitem) ++{ ++ inputFiles << iitem->getFilename(); ++} ++ ++void CToolExport::buildCmdFinal(QList& cmds) ++{ ++ switch(comboExport->currentIndex()) ++ { ++ case eTypeJnx: ++ buildCmdFinalJnx(cmds); ++ break; ++ ++ case eTypeRmap: ++ buildCmdFinalRmap(cmds); ++ break; ++ } ++} ++ ++void CToolExport::buildCmdFinalJnx(QList& cmds) ++{ ++ QStringList args; ++ args << "-q" << pageBirdsEyeJnx->getJpegQuality(); ++ args << "-s" << pageBirdsEyeJnx->getJpegSubsampling(); ++ args << "-p" << pageBirdsEyeJnx->getProductId(); ++ args << "-m" << pageBirdsEyeJnx->getProductName(); ++ args << "-n" << pageBirdsEyeJnx->getDescription(); ++ args << "-c" << pageBirdsEyeJnx->getCopyright(); ++ args << "-z" << pageBirdsEyeJnx->getZOrder(); ++ args += inputFiles; ++ ++ QString targetFile = lineTragetFile->text(); ++ QFileInfo fi(targetFile); ++ if(fi.suffix().toUpper() != "JNX") ++ { ++ targetFile += ".jnx"; ++ } ++ args << targetFile; ++ cmds << CShellCmd(IAppSetup::self().getQmtmap2jnx(), args); ++} ++ ++void CToolExport::buildCmdFinalRmap(QList& cmds) ++{ ++} ++ ++ ++void CToolExport::slotStart() ++{ ++ inputFiles.clear(); ++ ++ start(itemTree); ++ if(jobId > 0) ++ { ++ itemTree->setEnabled(false); ++ pushStart->setEnabled(false); ++ pushCancel->setEnabled(true); ++ } ++} ++ ++void CToolExport::slotFinished(qint32 id) ++{ ++ if(finished(id)) ++ { ++ itemTree->setEnabled(true); ++ pushStart->setEnabled(true); ++ pushCancel->setEnabled(false); ++ } ++} ++ +diff --git a/src/qmaptool/tool/CToolExport.h b/src/qmaptool/tool/CToolExport.h +new file mode 100644 +index 00000000..560370c8 +--- /dev/null ++++ b/src/qmaptool/tool/CToolExport.h +@@ -0,0 +1,63 @@ ++/********************************************************************************************** ++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CTOOLEXPORT_H ++#define CTOOLEXPORT_H ++ ++#include "items/IItem.h" ++#include "tool/ITool.h" ++#include "tool/IToolGui.h" ++#include "ui_IToolExport.h" ++ ++class CToolExport : public IToolGui, public ITool, private Ui::IToolExport ++{ ++ Q_OBJECT ++public: ++ CToolExport(QWidget * parent); ++ virtual ~CToolExport(); ++ ++ void setupChanged() override; ++ ++ FORWARD_TREE_ALL(itemTree) ++ ++private slots: ++ void slotMapSelectionChanged(); ++ void slotSomethingChanged(); ++ void slotStart(); ++ void slotFinished(qint32 id); ++ ++ void slotSelectFilename(); ++ ++private: ++ void buildCmd(QList& cmds, const IItem * iitem) override; ++ void buildCmdFinal(QList& cmds) override; ++ ++ void buildCmdFinalJnx(QList& cmds); ++ void buildCmdFinalRmap(QList& cmds); ++ ++ enum type_e ++ { ++ eTypeJnx = 0 ++ , eTypeRmap = 1 ++ }; ++ ++ QStringList inputFiles; ++}; ++ ++#endif //CTOOLEXPORT_H ++ +diff --git a/src/qmaptool/tool/CToolGrid.cpp b/src/qmaptool/tool/CToolGrid.cpp +new file mode 100644 +index 00000000..c232340a +--- /dev/null ++++ b/src/qmaptool/tool/CToolGrid.cpp +@@ -0,0 +1,124 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "CMainWindow.h" ++#include "items/CItemRefMap.h" ++#include "overlay/COverlayRefMap.h" ++#include "tool/CToolGrid.h" ++ ++#include ++ ++#define TESTITEM(cmd) \ ++ if(nullptr == item) \ ++ { \ ++ return cmd; \ ++ } \ ++ ++ ++CToolGrid::CToolGrid(QWidget *parent) ++ : QWidget(parent) ++{ ++ setupUi(this); ++ labelHelp->setText(tr("By placing 4 reference points at the corners of a grid " ++ "square and referencing them by their top left corner, " ++ "the width and height, all the other grid points can be " ++ "estimated.")); ++ ++ labelHelp->setVisible(CMainWindow::self().showToolHelp()->isChecked()); ++ connect(CMainWindow::self().showToolHelp(), &QAction::toggled, labelHelp, &QLabel::setVisible); ++ ++ connect(pushOk, &QPushButton::clicked, this, &CToolGrid::slotOk); ++ connect(pushCancel, &QPushButton::clicked, this, &CToolGrid::slotCancel); ++ connect(overlay, &COverlayGridTool::sigChanged, pushOk, &QPushButton::setEnabled); ++ connect(pushReset, &QPushButton::clicked, overlay, &COverlayGridTool::slotReset); ++} ++ ++void CToolGrid::registerItem(CItemRefMap * item) ++{ ++ this->item = item; ++ overlay->registerItem(item); ++} ++ ++bool CToolGrid::drawFx(QPainter& p, CCanvas::redraw_e needsRedraw) ++{ ++ TESTITEM(false) ++ item->drawFx(p, needsRedraw); ++ overlay->drawFx(p, needsRedraw); ++ ++ return true; ++} ++ ++void CToolGrid::mousePressEventFx(QMouseEvent *e) ++{ ++ TESTITEM() ++ item->CItemFile::mousePressEventFx(e); ++} ++ ++void CToolGrid::mouseMoveEventFx(QMouseEvent *e) ++{ ++ TESTITEM() ++ item->CItemFile::mouseMoveEventFx(e); ++ if(!item->getMapIsMoving()) ++ { ++ overlay->mouseMoveEventFx(e); ++ } ++} ++ ++void CToolGrid::mouseReleaseEventFx(QMouseEvent *e) ++{ ++ TESTITEM() ++ if(!item->getMapDidMove()) ++ { ++ overlay->mouseReleaseEventFx(e); ++ } ++ item->CItemFile::mouseReleaseEventFx(e); ++} ++ ++void CToolGrid::wheelEventFx(QWheelEvent *e) ++{ ++ TESTITEM() ++ item->CItemFile::wheelEventFx(e); ++} ++ ++void CToolGrid::leaveEventFx(QEvent *e) ++{ ++ TESTITEM() ++ item->CItemFile::leaveEventFx(e); ++ overlay->leaveEventFx(e); ++} ++ ++QCursor CToolGrid::getCursorFx() ++{ ++ TESTITEM(Qt::ArrowCursor) ++ return overlay->getCursorFx(); ++} ++ ++ ++void CToolGrid::slotOk() ++{ ++ TESTITEM() ++ item->addRefPoints(overlay->getRefPoints()); ++ slotCancel(); ++} ++ ++ ++void CToolGrid::slotCancel() ++{ ++ CMainWindow::self().showToolBox(); ++ registerItem(nullptr); ++} +diff --git a/src/qmaptool/tool/CToolGrid.h b/src/qmaptool/tool/CToolGrid.h +new file mode 100644 +index 00000000..4dd970ce +--- /dev/null ++++ b/src/qmaptool/tool/CToolGrid.h +@@ -0,0 +1,57 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CTOOLGRID_H ++#define CTOOLGRID_H ++ ++#include "tool/ITool.h" ++#include "ui_IToolGrid.h" ++ ++class CItemRefMap; ++ ++class CToolGrid : public QWidget, public ITool, private Ui::IToolGrid ++{ ++ Q_OBJECT ++public: ++ virtual ~CToolGrid() = default; ++ ++ bool drawFx(QPainter& p, CCanvas::redraw_e needsRedraw) override; ++ void mousePressEventFx(QMouseEvent *e) override; ++ void mouseMoveEventFx(QMouseEvent *e) override; ++ void mouseReleaseEventFx(QMouseEvent *e) override; ++ void wheelEventFx(QWheelEvent *e) override; ++ void leaveEventFx(QEvent *e) override; ++ QCursor getCursorFx() override; ++ ++ void setupChanged() override {} ++ ++ void registerItem(CItemRefMap * item); ++ ++private slots: ++ void slotOk(); ++ void slotCancel(); ++ ++private: ++ friend class CMainWindow; ++ CToolGrid(QWidget * parent); ++ ++ CItemRefMap * item = nullptr; ++}; ++ ++#endif //CTOOLGRID_H ++ +diff --git a/src/qmaptool/tool/CToolOverviewGroupBox.cpp b/src/qmaptool/tool/CToolOverviewGroupBox.cpp +new file mode 100644 +index 00000000..4ea7d417 +--- /dev/null ++++ b/src/qmaptool/tool/CToolOverviewGroupBox.cpp +@@ -0,0 +1,95 @@ ++/********************************************************************************************** ++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "setup/IAppSetup.h" ++#include "tool/CToolOverviewGroupBox.h" ++ ++#include ++ ++CToolOverviewGroupBox::CToolOverviewGroupBox(QWidget *parent) ++ : QGroupBox(parent) ++{ ++ setupUi(this); ++} ++ ++void CToolOverviewGroupBox::saveSettings(QSettings& cfg) ++{ ++ cfg.setValue("createOverviews", isChecked()); ++ cfg.setValue("by2", checkBy2->isChecked()); ++ cfg.setValue("by4", checkBy4->isChecked()); ++ cfg.setValue("by8", checkBy8->isChecked()); ++ cfg.setValue("by16", checkBy16->isChecked()); ++ cfg.setValue("by32", checkBy32->isChecked()); ++ cfg.setValue("by64", checkBy64->isChecked()); ++ cfg.setValue("useExternal", checkExternal->isChecked()); ++} ++ ++void CToolOverviewGroupBox::loadSettings(QSettings& cfg) ++{ ++ setChecked(cfg.value("createOverviews", false).toBool()); ++ checkBy2->setChecked(cfg.value("by2", false).toBool()); ++ checkBy4->setChecked(cfg.value("by4", false).toBool()); ++ checkBy8->setChecked(cfg.value("by8", false).toBool()); ++ checkBy16->setChecked(cfg.value("by16", false).toBool()); ++ checkBy32->setChecked(cfg.value("by32", false).toBool()); ++ checkBy64->setChecked(cfg.value("by64", false).toBool()); ++ checkExternal->setChecked(cfg.value("useExternal", true).toBool()); ++} ++ ++ ++void CToolOverviewGroupBox::buildCmd(QList& cmds, const QString& filename, const QString& resampling) ++{ ++ if(isChecked()) ++ { ++ QStringList args; ++ if(checkExternal->isChecked()) ++ { ++ args << "-ro"; ++ } ++ ++ args << "-r"; ++ args << resampling; ++ ++ args << filename; ++ if(checkBy2->isChecked()) ++ { ++ args << "2"; ++ } ++ if(checkBy4->isChecked()) ++ { ++ args << "4"; ++ } ++ if(checkBy8->isChecked()) ++ { ++ args << "8"; ++ } ++ if(checkBy16->isChecked()) ++ { ++ args << "16"; ++ } ++ if(checkBy32->isChecked()) ++ { ++ args << "32"; ++ } ++ if(checkBy64->isChecked()) ++ { ++ args << "64"; ++ } ++ cmds << CShellCmd(IAppSetup::self().getGdaladdo(), args); ++ } ++} +diff --git a/src/qmaptool/tool/CToolOverviewGroupBox.h b/src/qmaptool/tool/CToolOverviewGroupBox.h +new file mode 100644 +index 00000000..776a8a50 +--- /dev/null ++++ b/src/qmaptool/tool/CToolOverviewGroupBox.h +@@ -0,0 +1,43 @@ ++/********************************************************************************************** ++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CTOOLOVERVIEWGROUPBOX_H ++#define CTOOLOVERVIEWGROUPBOX_H ++ ++#include "shell/CShellCmd.h" ++ ++#include "ui_IToolOverviewGroupBox.h" ++ ++class QSettings; ++ ++class CToolOverviewGroupBox : public QGroupBox, private Ui::IToolOverviewGroupBox ++{ ++ Q_OBJECT ++public: ++ CToolOverviewGroupBox(QWidget * parent); ++ virtual ~CToolOverviewGroupBox() = default; ++ ++ void saveSettings(QSettings& cfg); ++ void loadSettings(QSettings& cfg); ++ ++ ++ void buildCmd(QList& cmds, const QString& filename, const QString &resampling); ++}; ++ ++#endif //CTOOLOVERVIEWGROUPBOX_H ++ +diff --git a/src/qmaptool/tool/CToolPalettize.cpp b/src/qmaptool/tool/CToolPalettize.cpp +new file mode 100644 +index 00000000..fd266c12 +--- /dev/null ++++ b/src/qmaptool/tool/CToolPalettize.cpp +@@ -0,0 +1,319 @@ ++/********************************************************************************************** ++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "CMainWindow.h" ++#include "helpers/CSettings.h" ++#include "items/CItemFile.h" ++#include "tool/CToolPalettize.h" ++ ++#include ++ ++CToolPalettize::CToolPalettize(QWidget *parent) ++ : IToolGui(parent) ++{ ++ setupUi(this); ++ setObjectName(tr("Add Color Palette")); ++ ++ lineFilename->addAction(actionFilename,QLineEdit::TrailingPosition); ++ ++ labelHelp->setText(tr("Usually you use RGBA color while referencing a map because the large " ++ "color space allows you to scale and rotate the map without any loss " ++ "of quality. But it results into rather large files. The file size can " ++ "be optimized by using a color palette instead of the RGBA color space. " ++ "The impact on quality is low as long as you do not want to scale or " ++ "rotate the map. If you want to combine files with a color palette all " ++ "files need to have the same palette." ++ )); ++ ++ labelHelp->setVisible(CMainWindow::self().showToolHelp()->isChecked()); ++ connect(CMainWindow::self().showToolHelp(), &QAction::toggled, labelHelp, &QLabel::setVisible); ++ ++ labelNote->setText(tr("Note: This tool will use all files in the list as a combined input " ++ "to derive an optimal palette. This will only work if all files have " ++ "the same projection and scale." ++ )); ++ labelNote->setVisible(CMainWindow::self().showToolHelp()->isChecked()); ++ connect(CMainWindow::self().showToolHelp(), &QAction::toggled, labelNote, &QLabel::setVisible); ++ ++ connect(itemList, &CItemListWidget::sigAddItem, this, &CToolPalettize::slotAddItem); ++ connect(itemList, &CItemListWidget::sigSelectionChanged, this, &CToolPalettize::slotMapSelectionChanged); ++ connect(itemList, &CItemListWidget::sigChanged, this, &CToolPalettize::slotSomethingChanged); ++ ++ connect(radioSingle, &QRadioButton::toggled, lineSuffix, &QLineEdit::setEnabled); ++ connect(radioSingle, &QRadioButton::toggled, this, &CToolPalettize::slotSomethingChanged); ++ connect(radioCombined, &QRadioButton::toggled, lineFilename, &QLineEdit::setEnabled); ++ connect(radioCombined, &QRadioButton::toggled, this, &CToolPalettize::slotSomethingChanged); ++ ++ connect(actionFilename, &QAction::triggered, this, &CToolPalettize::slotSelectFilename); ++ connect(lineSuffix, &QLineEdit::textChanged, this, &CToolPalettize::slotSomethingChanged); ++ connect(lineFilename, &QLineEdit::textChanged, this, &CToolPalettize::slotSomethingChanged); ++ ++ connect(pushStart, &QPushButton::clicked, this, &CToolPalettize::slotStart); ++ connect(pushCancel, &QPushButton::clicked, &CShell::self(), &CShell::slotCancel); ++ connect(&CShell::self(), &CShell::sigFinishedJob, this, &CToolPalettize::slotFinished); ++ ++ setupChanged(); ++ ++ SETTINGS; ++ cfg.beginGroup("ToolPalettize"); ++ itemList->loadSettings(cfg); ++ checkCreateVrt->setChecked(cfg.value("createVrt", false).toBool()); ++ groupOverviews->loadSettings(cfg); ++ radioSingle->setChecked(cfg.value("singleFiles", true).toBool()); ++ radioCombined->setChecked(cfg.value("combinedFile", false).toBool()); ++ lineFilename->setText(cfg.value("filename","").toString()); ++ lineSuffix->setText(cfg.value("suffix","_8bit").toString()); ++ cfg.endGroup(); ++ ++ lineFilename->setEnabled(radioCombined->isChecked()); ++ lineSuffix->setEnabled(radioSingle->isChecked()); ++ ++ inputFileList1 = new QTemporaryFile(this); ++ inputFileList2 = new QTemporaryFile(this); ++} ++ ++CToolPalettize::~CToolPalettize() ++{ ++ SETTINGS; ++ cfg.beginGroup("ToolPalettize"); ++ cfg.remove(""); ++ itemList->saveSettings(cfg); ++ cfg.setValue("createVrt", checkCreateVrt->isChecked()); ++ groupOverviews->saveSettings(cfg); ++ cfg.setValue("singleFiles", radioSingle->isChecked()); ++ cfg.setValue("combinedFile", radioCombined->isChecked()); ++ cfg.setValue("filename", lineFilename->text()); ++ cfg.setValue("suffix", lineSuffix->text()); ++ cfg.endGroup(); ++} ++ ++void CToolPalettize::slotSelectFilename() ++{ ++ SETTINGS; ++ QString path = cfg.value("Path/mapInput", QDir::homePath()).toString(); ++ QString filename = QFileDialog::getSaveFileName(this, tr("Select filename..."), path); ++ if(filename.isEmpty()) ++ { ++ return; ++ } ++ cfg.setValue("Path/mapInput", QFileInfo(filename).absolutePath()); ++ ++ if(!filename.toUpper().endsWith(".TIF")) ++ { ++ filename += ".tif"; ++ } ++ ++ lineFilename->setText(filename); ++} ++ ++void CToolPalettize::setupChanged() ++{ ++ bool hasGdaladdo = !IAppSetup::self().getGdaladdo().isEmpty(); ++ labelNoGdaladdo->setVisible(!hasGdaladdo); ++ ++ bool hasGdaltranslate = !IAppSetup::self().getGdaltranslate().isEmpty(); ++ labelNoGdaltranslate->setVisible(!hasGdaltranslate); ++ ++ bool hasQmtrgb2pct = !IAppSetup::self().getQmtrgb2pct().isEmpty(); ++ labelNoQmtrgb2pct->setVisible(!hasQmtrgb2pct); ++ ++ frame->setVisible(hasGdaladdo && hasQmtrgb2pct && hasGdaltranslate); ++} ++ ++void CToolPalettize::slotAddItem(const QString& filename, QListWidget * list) ++{ ++ CItemFile * item = new CItemFile(filename, list); ++ connect(item, &CItemFile::sigChanged, itemList, &CItemListWidget::sigChanged); ++} ++ ++void CToolPalettize::slotMapSelectionChanged() ++{ ++ CMainWindow::self().getCanvas()->slotTriggerCompleteUpdate(CCanvas::eRedrawAll); ++ slotSomethingChanged(); ++} ++ ++void CToolPalettize::slotSomethingChanged() ++{ ++ bool ok = itemList->count() > 0; ++ if(radioSingle->isChecked() && lineSuffix->text().isEmpty()) ++ { ++ ok = false; ++ } ++ if(radioCombined->isChecked() && lineFilename->text().isEmpty()) ++ { ++ ok = false; ++ } ++ ++ pushStart->setEnabled(ok); ++} ++ ++void CToolPalettize::buildCmd(QList& cmds, const IItem * iitem) ++{ ++ inputFileList1->open(); ++ QTextStream stream(inputFileList1); ++ stream << iitem->getFilename() << endl; ++ inputFileList1->close(); ++} ++ ++void CToolPalettize::buildCmdFinal(QList& cmds) ++{ ++ QStringList args; ++ ++ // ---- command 1 ---------------------- ++ QString vrtFilename = createTempFile("vrt"); ++ args.clear(); ++ args << vrtFilename; ++ args << "-input_file_list" << inputFileList1->fileName(); ++ cmds << CShellCmd(IAppSetup::self().getGdalbuildvrt(), args); ++ ++ // ---- command 2 ---------------------- ++ QString pctFilename = createTempFile("vrt"); ++ args.clear(); ++ args << "--sct" << pctFilename; ++ args << vrtFilename; ++ cmds << CShellCmd(IAppSetup::self().getQmtrgb2pct(), args); ++ ++ // ---- command 2..2 + N ---------------------- ++ if(radioCombined->isChecked()) ++ { ++ inputFileList2->open(); ++ QTextStream stream(inputFileList2); ++ ++ const int N = itemList->count(); ++ for(int n = 0; n < N; n++) ++ { ++ const IItem * item = dynamic_cast(itemList->item(n)); ++ if(nullptr == item) ++ { ++ continue; ++ } ++ QString inFilename = item->getFilename(); ++ QString outFilename = createTempFile("tif"); ++ ++ stream << outFilename << endl; ++ ++ args.clear(); ++ args << "--pct" << pctFilename; ++ args << inFilename; ++ args << outFilename; ++ cmds << CShellCmd(IAppSetup::self().getQmtrgb2pct(), args); ++ } ++ ++ inputFileList2->close(); ++ ++ // ---- command 2 + N + 1 ---------------------- ++ QString vrtFilename = createTempFile("vrt"); ++ args.clear(); ++ args << vrtFilename; ++ args << "-input_file_list" << inputFileList2->fileName(); ++ cmds << CShellCmd(IAppSetup::self().getGdalbuildvrt(), args); ++ ++ // ---- command 2 + N + 2 ---------------------- ++ QString outFilename = lineFilename->text(); ++ if(!outFilename.toUpper().endsWith(".TIF")) ++ { ++ outFilename += ".tif"; ++ } ++ ++ args.clear(); ++ args << "-co" << "TILED=YES"; ++ args << "-co" << "COMPRESS=LZW"; ++ args << vrtFilename; ++ args << outFilename; ++ cmds << CShellCmd(IAppSetup::self().getGdaltranslate(), args); ++ ++ QString lastOutFilname = outFilename; ++ // ---- command 2 + N + 3 ---------------------- ++ if(checkCreateVrt->isChecked()) ++ { ++ QFileInfo fi(outFilename); ++ QString vrtFilename = fi.absoluteDir().absoluteFilePath(fi.completeBaseName() + ".vrt"); ++ args.clear(); ++ args << vrtFilename << outFilename; ++ cmds << CShellCmd(IAppSetup::self().getGdalbuildvrt(), args); ++ lastOutFilname = vrtFilename; ++ } ++ ++ // ---- command 2 + N + 4 ---------------------- ++ groupOverviews->buildCmd(cmds, lastOutFilname, "nearest"); ++ } ++ else ++ { ++ // ---- command 3..3*N ---------------------- ++ const int N = itemList->count(); ++ for(int n = 0; n < N; n++) ++ { ++ const IItem * item = dynamic_cast(itemList->item(n)); ++ if(nullptr == item) ++ { ++ continue; ++ } ++ QString inFilename = item->getFilename(); ++ QFileInfo fi(inFilename); ++ QString outFilename = fi.absoluteDir().absoluteFilePath(fi.completeBaseName() + lineSuffix->text() + "." + fi.suffix()); ++ ++ // ---- command n*3 ---------------------- ++ args.clear(); ++ args << "--pct" << pctFilename; ++ args << inFilename; ++ args << outFilename; ++ cmds << CShellCmd(IAppSetup::self().getQmtrgb2pct(), args); ++ ++ QString lastOutFilname = outFilename; ++ // ---- command n*3 + 1 ---------------------- ++ if(checkCreateVrt->isChecked()) ++ { ++ QFileInfo fi(outFilename); ++ QString vrtFilename = fi.absoluteDir().absoluteFilePath(fi.completeBaseName() + ".vrt"); ++ args.clear(); ++ args << vrtFilename << outFilename; ++ cmds << CShellCmd(IAppSetup::self().getGdalbuildvrt(), args); ++ lastOutFilname = vrtFilename; ++ } ++ ++ // ---- command n*3 + 2 ---------------------- ++ groupOverviews->buildCmd(cmds, lastOutFilname, "nearest"); ++ } ++ } ++} ++ ++void CToolPalettize::slotStart() ++{ ++ // reset file with list of input files ++ inputFileList1->open(); ++ inputFileList1->resize(0); ++ inputFileList1->close(); ++ ++ start(itemList, true); ++ if(jobId > 0) ++ { ++ itemList->setEnabled(false); ++ pushStart->setEnabled(false); ++ pushCancel->setEnabled(true); ++ } ++} ++ ++void CToolPalettize::slotFinished(qint32 id) ++{ ++ if(finished(id)) ++ { ++ itemList->setEnabled(true); ++ pushStart->setEnabled(true); ++ pushCancel->setEnabled(false); ++ } ++} +diff --git a/src/qmaptool/tool/CToolPalettize.h b/src/qmaptool/tool/CToolPalettize.h +new file mode 100644 +index 00000000..d518faf7 +--- /dev/null ++++ b/src/qmaptool/tool/CToolPalettize.h +@@ -0,0 +1,57 @@ ++/********************************************************************************************** ++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CTOOLPALETTIZE_H ++#define CTOOLPALETTIZE_H ++ ++#include "items/IItem.h" ++#include "tool/ITool.h" ++#include "tool/IToolGui.h" ++#include "ui_IToolPalettize.h" ++ ++class CToolPalettize : public IToolGui, public ITool, private Ui::IToolPalettize ++{ ++ Q_OBJECT ++public: ++ CToolPalettize(QWidget * parent); ++ virtual ~CToolPalettize(); ++ ++ void setupChanged() override; ++ ++ FORWARD_LIST_ALL(itemList) ++ ++private slots: ++ void slotAddItem(const QString& filename, QListWidget * list); ++ void slotMapSelectionChanged(); ++ void slotSomethingChanged(); ++ void slotStart(); ++ void slotFinished(qint32 id); ++ ++ void slotSelectFilename(); ++ ++private: ++ void buildCmd(QList& cmds, const IItem * iitem) override; ++ void buildCmdFinal(QList& cmds) override; ++ ++ //QStringList inputFiles; ++ QTemporaryFile * inputFileList1; ++ QTemporaryFile * inputFileList2; ++}; ++ ++#endif //CTOOLPALETTIZE_H ++ +diff --git a/src/qmaptool/tool/CToolRefMap.cpp b/src/qmaptool/tool/CToolRefMap.cpp +new file mode 100644 +index 00000000..5b1b87b4 +--- /dev/null ++++ b/src/qmaptool/tool/CToolRefMap.cpp +@@ -0,0 +1,257 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "canvas/IDrawContext.h" ++#include "CMainWindow.h" ++#include "CToolRefMap.h" ++#include "helpers/CSettings.h" ++#include "items/CItemRefMap.h" ++#include "overlay/refmap/COverlayRefMapPoint.h" ++#include "setup/IAppSetup.h" ++#include "shell/CShell.h" ++ ++#include ++ ++CToolRefMap::CToolRefMap(QWidget *parent) ++ : IToolGui(parent) ++{ ++ setupUi(this); ++ setObjectName(tr("Reference Map")); ++ ++ labelHelp->setText(tr("A scan of a paper map can be converted to a referenced raster map if " ++ "you place at least three reference points on the map. The more points " ++ "the better the result. If your map has a grid you can place points on " ++ "that grid with the grid tool.")); ++ ++ labelHelp->setVisible(CMainWindow::self().showToolHelp()->isChecked()); ++ connect(CMainWindow::self().showToolHelp(), &QAction::toggled, labelHelp, &QLabel::setVisible); ++ ++ connect(itemList, &CItemListWidget::sigAddItem, this, &CToolRefMap::slotAddItem); ++ connect(itemList, &CItemListWidget::sigSelectionChanged, this, &CToolRefMap::slotMapSelectionChanged); ++ connect(itemList, &CItemListWidget::sigChanged, this, &CToolRefMap::slotSomethingChanged); ++ ++ connect(lineSuffix, &QLineEdit::textChanged, this, &CToolRefMap::slotSomethingChanged); ++ ++ connect(pushStart, &QPushButton::clicked, this, &CToolRefMap::slotStart); ++ connect(pushCancel, &QPushButton::clicked, &CShell::self(), &CShell::slotCancel); ++ connect(&CShell::self(), &CShell::sigFinishedJob, this, &CToolRefMap::slotFinished); ++ ++ setupChanged(); ++ ++ SETTINGS; ++ cfg.beginGroup("ToolRefMap"); ++ itemList->loadSettings(cfg); ++ checkCreateVrt->setChecked(cfg.value("createVrt", false).toBool()); ++ groupOverviews->loadSettings(cfg); ++ checkAllFiles->setChecked(cfg.value("allFiles", false).toBool()); ++ lineSuffix->setText(cfg.value("suffix","_ref").toString()); ++ cfg.endGroup(); ++ ++ slotSomethingChanged(); ++ ++ adjustSize(); ++} ++ ++CToolRefMap::~CToolRefMap() ++{ ++ SETTINGS; ++ cfg.beginGroup("ToolRefMap"); ++ cfg.remove(""); ++ itemList->saveSettings(cfg); ++ cfg.setValue("createVrt", checkCreateVrt->isChecked()); ++ groupOverviews->saveSettings(cfg); ++ cfg.setValue("allFiles", checkAllFiles->isChecked()); ++ cfg.setValue("suffix", lineSuffix->text()); ++ cfg.endGroup(); ++} ++ ++ ++void CToolRefMap::setupChanged() ++{ ++ bool hasGdalwarp = !IAppSetup::self().getGdalwarp().isEmpty(); ++ labelNoGdalwarp->setVisible(!hasGdalwarp); ++ ++ bool hasGdaltranslate = !IAppSetup::self().getGdaltranslate().isEmpty(); ++ labelNoGdalTranslate->setVisible(!hasGdaltranslate); ++ ++ bool hasGdaladdo = !IAppSetup::self().getGdaladdo().isEmpty(); ++ labelNoGdaladdo->setVisible(!hasGdaladdo); ++ ++ frame->setVisible(hasGdalwarp && hasGdaltranslate && hasGdaladdo); ++ ++ checkCreateVrt->setVisible(!IAppSetup::self().getGdalbuildvrt().isEmpty()); ++} ++ ++void CToolRefMap::slotAddItem(const QString& filename, QListWidget * list) ++{ ++ CItemRefMap * item = new CItemRefMap(filename, stackedWidget, list); ++ connect(item, &CItemFile::sigChanged, itemList, &CItemListWidget::sigChanged); ++} ++ ++void CToolRefMap::slotMapSelectionChanged() ++{ ++ CMainWindow::self().getCanvas()->slotTriggerCompleteUpdate(CCanvas::eRedrawAll); ++ slotSomethingChanged(); ++} ++ ++void CToolRefMap::slotSomethingChanged() ++{ ++ IItem * item = itemList->currentItem(); ++ if(item != nullptr) ++ { ++ bool ok = item->isOk(); ++ if(lineSuffix->text().isEmpty()) ++ { ++ ok = false; ++ } ++ pushStart->setEnabled(ok); ++ } ++ else ++ { ++ pushStart->setEnabled(false); ++ } ++} ++ ++void CToolRefMap::buildCmd(QList& cmds, const IItem *iitem) ++{ ++ const CItemRefMap * item = dynamic_cast(iitem); ++ if(nullptr == item) ++ { ++ return; ++ } ++ ++ projPJ pjsrc = pj_init_plus("+proj=longlat +datum=WGS84 +no_defs"); ++ if(pjsrc == nullptr) ++ { ++ return; ++ } ++ ++ projPJ pjtar = pj_init_plus(item->getMapProjection().toLatin1()); ++ if(pjtar == nullptr) ++ { ++ pj_free(pjsrc); ++ return; ++ } ++ ++ // ---- command 1 ---------------------- ++ QStringList args; ++ args << "-a_srs" << item->getMapProjection(); ++ ++ const QList& points = item->getRefPoints(); ++ for(const COverlayRefMapPoint* pt : points) ++ { ++ qreal lon = pt->getPtRef().x() * DEG_TO_RAD; ++ qreal lat = pt->getPtRef().y() * DEG_TO_RAD; ++ pj_transform(pjsrc, pjtar, 1, 0, &lon, &lat, 0); ++ ++ args << "-gcp"; ++ args << QString::number(pt->getPtPtx().x()); ++ args << QString::number(pt->getPtPtx().y()); ++ ++ args << QString::number(lon,'f',6); ++ args << QString::number(lat,'f',6); ++ args << "0"; ++ } ++ ++ QString tmpname1 = createTempFile("tif"); ++ QString inFilename = item->getFilename(); ++ args << inFilename << tmpname1; ++ cmds << CShellCmd(IAppSetup::self().getGdaltranslate(), args); ++ ++ // ---- command 2 ---------------------- ++ IDrawContext * context = item->getDrawContext(); ++ args.clear(); ++ // --- set re-sampling method --- ++ args << "-r"; ++ args << (context->is32BitRgb() ? "cubic" : "near"); ++ // --- overwrite last output file --- ++ args << "-overwrite"; ++ // --- use all CPU cores when possible --- ++ args << "-multi"; ++ args << "-wo"; ++ args << "NUM_THREADS=ALL_CPUS"; ++ // --- define transparent color --- ++ if(context->getRasterBandCount() == 1) ++ { ++ if(!context->getNoData()) ++ { ++ // --- use no data value for destination, too --- ++ args << "-dstnodata" << "255"; ++ } ++ } ++ else if(context->getRasterBandCount() == 3) ++ { ++ // --- add alpha channel to files with just RGB --- ++ args << "-dstalpha"; ++ } ++ ++ QString tmpname2 = createTempFile("tif"); ++ args << tmpname1 << tmpname2; ++ cmds << CShellCmd(IAppSetup::self().getGdalwarp(), args); ++ ++ // ---- command 3 ---------------------- ++ QFileInfo fi(inFilename); ++ QString outFilename = fi.absoluteDir().absoluteFilePath(fi.completeBaseName() + lineSuffix->text() + "." + fi.suffix()); ++ ++ args.clear(); ++ args << "-co" << "tiled=yes" << "-co" << "compress=deflate"; ++ args << tmpname2 << outFilename; ++ cmds << CShellCmd(IAppSetup::self().getGdaltranslate(), args); ++ ++ QString lastOutFilname = outFilename; ++ // ---- command 4 ---------------------- ++ if(checkCreateVrt->isChecked()) ++ { ++ QFileInfo fi(outFilename); ++ QString vrtFilename = fi.absoluteDir().absoluteFilePath(fi.completeBaseName() + ".vrt"); ++ args.clear(); ++ args << vrtFilename << outFilename; ++ cmds << CShellCmd(IAppSetup::self().getGdalbuildvrt(), args); ++ lastOutFilname = vrtFilename; ++ } ++ ++ // ---- command 5 ---------------------- ++ groupOverviews->buildCmd(cmds, lastOutFilname, context->is32BitRgb() ? "cubic" : "nearest"); ++ ++ pj_free(pjsrc); ++ pj_free(pjtar); ++} ++ ++void CToolRefMap::slotStart() ++{ ++ start(itemList, checkAllFiles->isChecked()); ++ if(jobId > 0) ++ { ++ itemList->setEnabled(false); ++ frameInput->setEnabled(false); ++ pushStart->setEnabled(false); ++ pushCancel->setEnabled(true); ++ } ++} ++ ++void CToolRefMap::slotFinished(qint32 id) ++{ ++ if(finished(id)) ++ { ++ itemList->setEnabled(true); ++ frameInput->setEnabled(true); ++ pushStart->setEnabled(true); ++ pushCancel->setEnabled(false); ++ } ++} ++ +diff --git a/src/qmaptool/tool/CToolRefMap.h b/src/qmaptool/tool/CToolRefMap.h +new file mode 100644 +index 00000000..2f009b34 +--- /dev/null ++++ b/src/qmaptool/tool/CToolRefMap.h +@@ -0,0 +1,52 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CTOOLREFMAP_H ++#define CTOOLREFMAP_H ++ ++#include "items/IItem.h" ++#include "tool/ITool.h" ++#include "tool/IToolGui.h" ++#include "ui_IToolRefMap.h" ++ ++ ++class CToolRefMap : public IToolGui, public ITool, private Ui::IToolRefMap ++{ ++ Q_OBJECT ++public: ++ CToolRefMap(QWidget * parent); ++ virtual ~CToolRefMap(); ++ ++ void setupChanged() override; ++ ++ FORWARD_LIST_ALL(itemList) ++ ++ ++private slots: ++ void slotAddItem(const QString& filename, QListWidget * list); ++ void slotMapSelectionChanged(); ++ void slotSomethingChanged(); ++ void slotStart(); ++ void slotFinished(qint32 id); ++ ++private: ++ void buildCmd(QList& cmds, const IItem * iitem) override; ++}; ++ ++#endif //CTOOLREFMAP_H ++ +diff --git a/src/qmaptool/tool/CToolStack.cpp b/src/qmaptool/tool/CToolStack.cpp +new file mode 100644 +index 00000000..47cc916d +--- /dev/null ++++ b/src/qmaptool/tool/CToolStack.cpp +@@ -0,0 +1,44 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "CMainWindow.h" ++#include "tool/CToolStack.h" ++ ++CToolStack::CToolStack(QWidget * parent) ++ : QStackedWidget(parent) ++{ ++ connect(this, &CToolStack::currentChanged, this, &CToolStack::slotToolChanged); ++} ++ ++void CToolStack::setupChanged() ++{ ++ const int N = count(); ++ for(int n = 0; n < N; n++) ++ { ++ ITool * tool = dynamic_cast(widget(n)); ++ if(nullptr != tool) ++ { ++ tool->setupChanged(); ++ } ++ } ++} ++ ++void CToolStack::slotToolChanged(int idx) ++{ ++ CMainWindow::self().getCanvas()->slotTriggerCompleteUpdate(CCanvas::eRedrawAll); ++} +diff --git a/src/qmaptool/tool/CToolStack.h b/src/qmaptool/tool/CToolStack.h +new file mode 100644 +index 00000000..f0af7d28 +--- /dev/null ++++ b/src/qmaptool/tool/CToolStack.h +@@ -0,0 +1,41 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CTOOLSTACK_H ++#define CTOOLSTACK_H ++ ++ ++#include "tool/ITool.h" ++#include ++ ++class CToolStack : public ITool, public QStackedWidget ++{ ++public: ++ CToolStack(QWidget * parent); ++ virtual ~CToolStack() = default; ++ ++ void setupChanged() override; ++ ++ FORWARD_WIDGET_ALL() ++ ++private slots: ++ void slotToolChanged(int idx); ++}; ++ ++#endif //CTOOLSTACK_H ++ +diff --git a/src/qmaptool/tool/ITool.cpp b/src/qmaptool/tool/ITool.cpp +new file mode 100644 +index 00000000..157c999a +--- /dev/null ++++ b/src/qmaptool/tool/ITool.cpp +@@ -0,0 +1,20 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "tool/ITool.h" ++ +diff --git a/src/qmaptool/tool/ITool.h b/src/qmaptool/tool/ITool.h +new file mode 100644 +index 00000000..b2c43672 +--- /dev/null ++++ b/src/qmaptool/tool/ITool.h +@@ -0,0 +1,234 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef ITOOL_H ++#define ITOOL_H ++ ++#include "canvas/CCanvas.h" ++#include "setup/IAppSetup.h" ++#include "shell/CShellCmd.h" ++#include ++#include ++class QPainter; ++class QMouseEvent; ++class QWheelEvent; ++class QEvent; ++class CItemListWidget; ++class IItem; ++ ++#define FORWARD_WIDGET_VOID(cmd) \ ++ ITool * tool = dynamic_cast(currentWidget()); \ ++ if(nullptr != tool) \ ++ { \ ++ tool->cmd; \ ++ } \ ++ ++#define FORWARD_WIDGET_RETURN(cmd, def) \ ++ ITool * tool = dynamic_cast(currentWidget()); \ ++ if(nullptr != tool) \ ++ { \ ++ return tool->cmd; \ ++ } \ ++ return def; \ ++ ++#define FORWARD_WIDGET_ALL() \ ++ bool drawFx(QPainter& p, CCanvas::redraw_e needsRedraw) override \ ++ { \ ++ FORWARD_WIDGET_RETURN(drawFx(p, needsRedraw), false) \ ++ } \ ++ void mousePressEventFx(QMouseEvent *e) override \ ++ { \ ++ FORWARD_WIDGET_VOID(mousePressEventFx(e)) \ ++ } \ ++ void mouseMoveEventFx(QMouseEvent *e) override \ ++ { \ ++ FORWARD_WIDGET_VOID(mouseMoveEventFx(e)) \ ++ } \ ++ void mouseReleaseEventFx(QMouseEvent *e) override \ ++ { \ ++ FORWARD_WIDGET_VOID(mouseReleaseEventFx(e)) \ ++ } \ ++ void mouseDoubleClickEventFx(QMouseEvent *e) override \ ++ { \ ++ FORWARD_WIDGET_VOID(mouseDoubleClickEventFx(e)) \ ++ } \ ++ void wheelEventFx(QWheelEvent *e) override \ ++ { \ ++ FORWARD_WIDGET_VOID(wheelEventFx(e)) \ ++ } \ ++ void enterEventFx(QEvent *e) override \ ++ { \ ++ FORWARD_WIDGET_VOID(enterEventFx(e)) \ ++ } \ ++ void leaveEventFx(QEvent *e) override \ ++ { \ ++ FORWARD_WIDGET_VOID(leaveEventFx(e)) \ ++ } \ ++ QCursor getCursorFx() override \ ++ { \ ++ FORWARD_WIDGET_RETURN(getCursorFx(), Qt::ArrowCursor) \ ++ } \ ++ bool keyPressEventFx(QKeyEvent * e) override \ ++ { \ ++ FORWARD_WIDGET_RETURN(keyPressEventFx(e), false) \ ++ } \ ++ ++ ++#define FORWARD_LIST_VOID(list, cmd) \ ++ ITool * tool = dynamic_cast(list->currentItem()); \ ++ if(nullptr != tool) \ ++ { \ ++ tool->cmd; \ ++ } \ ++ ++#define FORWARD_LIST_RETURN(list, cmd, def) \ ++ ITool * tool = dynamic_cast(list->currentItem()); \ ++ if(nullptr != tool) \ ++ { \ ++ return tool->cmd; \ ++ } \ ++ return def; \ ++ ++ ++#define FORWARD_LIST_ALL(list) \ ++ bool drawFx(QPainter& p, CCanvas::redraw_e needsRedraw) override \ ++ { \ ++ FORWARD_LIST_RETURN(list, drawFx(p, needsRedraw), false) \ ++ } \ ++ void mousePressEventFx(QMouseEvent *e) override \ ++ { \ ++ FORWARD_LIST_VOID(list, mousePressEventFx(e)) \ ++ } \ ++ void mouseMoveEventFx(QMouseEvent *e) override \ ++ { \ ++ FORWARD_LIST_VOID(list, mouseMoveEventFx(e)) \ ++ } \ ++ void mouseReleaseEventFx(QMouseEvent *e) override \ ++ { \ ++ FORWARD_LIST_VOID(list, mouseReleaseEventFx(e)) \ ++ } \ ++ void mouseDoubleClickEventFx(QMouseEvent *e) override \ ++ { \ ++ FORWARD_LIST_VOID(list, mouseDoubleClickEventFx(e)) \ ++ } \ ++ void wheelEventFx(QWheelEvent *e) override \ ++ { \ ++ FORWARD_LIST_VOID(list, wheelEventFx(e)) \ ++ } \ ++ void enterEventFx(QEvent *e) override \ ++ { \ ++ FORWARD_LIST_VOID(list, enterEventFx(e)) \ ++ } \ ++ void leaveEventFx(QEvent *e) override \ ++ { \ ++ FORWARD_LIST_VOID(list, leaveEventFx(e)) \ ++ } \ ++ QCursor getCursorFx() override \ ++ { \ ++ FORWARD_LIST_RETURN(list, getCursorFx(), Qt::ArrowCursor) \ ++ } \ ++ bool keyPressEventFx(QKeyEvent * e) override \ ++ { \ ++ FORWARD_LIST_RETURN(list, keyPressEventFx(e), false) \ ++ } \ ++ ++#define FORWARD_TREE_VOID(tree, cmd) \ ++ ITool * tool = dynamic_cast(tree->currentItem()); \ ++ if(nullptr != tool) \ ++ { \ ++ tool->cmd; \ ++ } \ ++ ++#define FORWARD_TREE_RETURN(tree, cmd, def) \ ++ ITool * tool = dynamic_cast(tree->currentItem()); \ ++ if(nullptr != tool) \ ++ { \ ++ return tool->cmd; \ ++ } \ ++ return def; \ ++ ++#define FORWARD_TREE_ALL(tree) \ ++ bool drawFx(QPainter& p, CCanvas::redraw_e needsRedraw) override \ ++ { \ ++ return tree->drawFx(p, needsRedraw); \ ++ } \ ++ void mousePressEventFx(QMouseEvent *e) override \ ++ { \ ++ FORWARD_TREE_VOID(tree, mousePressEventFx(e)) \ ++ } \ ++ void mouseMoveEventFx(QMouseEvent *e) override \ ++ { \ ++ FORWARD_TREE_VOID(tree, mouseMoveEventFx(e)) \ ++ } \ ++ void mouseReleaseEventFx(QMouseEvent *e) override \ ++ { \ ++ FORWARD_TREE_VOID(tree, mouseReleaseEventFx(e)) \ ++ } \ ++ void mouseDoubleClickEventFx(QMouseEvent *e) override \ ++ { \ ++ FORWARD_TREE_VOID(tree, mouseDoubleClickEventFx(e)) \ ++ } \ ++ void wheelEventFx(QWheelEvent *e) override \ ++ { \ ++ FORWARD_TREE_VOID(tree, wheelEventFx(e)) \ ++ } \ ++ void enterEventFx(QEvent *e) override \ ++ { \ ++ FORWARD_TREE_VOID(tree, enterEventFx(e)) \ ++ } \ ++ void leaveEventFx(QEvent *e) override \ ++ { \ ++ FORWARD_TREE_VOID(tree, leaveEventFx(e)) \ ++ } \ ++ QCursor getCursorFx() override \ ++ { \ ++ FORWARD_TREE_RETURN(tree, getCursorFx(), Qt::ArrowCursor) \ ++ } \ ++ bool keyPressEventFx(QKeyEvent * e) override \ ++ { \ ++ FORWARD_TREE_RETURN(tree, keyPressEventFx(e), false) \ ++ } \ ++ ++class ITool ++{ ++public: ++ ITool() ++ { ++ } ++ virtual ~ITool() = default; ++ ++ virtual bool drawFx(QPainter& p, CCanvas::redraw_e needsRedraw) = 0; ++ virtual void setupChanged() = 0; ++ ++ virtual void mousePressEventFx(QMouseEvent *e) {} ++ virtual void mouseMoveEventFx(QMouseEvent *e){} ++ virtual void mouseReleaseEventFx(QMouseEvent *e){} ++ virtual void mouseDoubleClickEventFx(QMouseEvent *e){} ++ virtual void wheelEventFx(QWheelEvent *e){} ++ virtual void enterEventFx(QEvent *e){} ++ virtual void leaveEventFx(QEvent *e){} ++ virtual bool keyPressEventFx(QKeyEvent *e){return false; } ++ ++ virtual QCursor getCursorFx() ++ { ++ return Qt::ArrowCursor; ++ } ++}; ++ ++#endif //ITOOL_H ++ +diff --git a/src/qmaptool/tool/IToolAddOverview.ui b/src/qmaptool/tool/IToolAddOverview.ui +new file mode 100644 +index 00000000..346fb216 +--- /dev/null ++++ b/src/qmaptool/tool/IToolAddOverview.ui +@@ -0,0 +1,278 @@ ++ ++ ++ IToolAddOverview ++ ++ ++ ++ 0 ++ 0 ++ 400 ++ 601 ++ ++ ++ ++ Form ++ ++ ++ ++ 3 ++ ++ ++ 3 ++ ++ ++ 3 ++ ++ ++ 3 ++ ++ ++ 3 ++ ++ ++ ++ ++ QFrame::NoFrame ++ ++ ++ QFrame::Plain ++ ++ ++ ++ 3 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ ++ ++ do not translate ++ ++ ++ Qt::RichText ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ QFrame::NoFrame ++ ++ ++ QFrame::Plain ++ ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ ++ ++ ++ ++ QFrame::NoFrame ++ ++ ++ QFrame::Plain ++ ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ ++ ++ :2 ++ ++ ++ ++ ++ ++ ++ :4 ++ ++ ++ ++ ++ ++ ++ :8 ++ ++ ++ ++ ++ ++ ++ :16 ++ ++ ++ ++ ++ ++ ++ :32 ++ ++ ++ ++ ++ ++ ++ :64 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Remove all overview levels from map file. ++ ++ ++ Remove ++ ++ ++ ++ ++ ++ ++ Do not copy the overviews into the file itself. Add them as external file. ++ ++ ++ Overview as external file ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Qt::Vertical ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ false ++ ++ ++ Start ++ ++ ++ ++ :/icons/32x32/Apply.png:/icons/32x32/Apply.png ++ ++ ++ ++ ++ ++ ++ false ++ ++ ++ Cancel ++ ++ ++ ++ :/icons/32x32/Cancel.png:/icons/32x32/Cancel.png ++ ++ ++ ++ ++ ++ ++ For all files ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ 40 ++ 20 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ <b style='color: red;'>No "gdaladdo" found. Please check setup!</b> ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ ++ CItemListWidget ++ QWidget ++
items/CItemListWidget.h
++ 1 ++
++
++ ++ ++ ++ ++
+diff --git a/src/qmaptool/tool/IToolCutMap.ui b/src/qmaptool/tool/IToolCutMap.ui +new file mode 100644 +index 00000000..75f9b23d +--- /dev/null ++++ b/src/qmaptool/tool/IToolCutMap.ui +@@ -0,0 +1,263 @@ ++ ++ ++ IToolCutMap ++ ++ ++ ++ 0 ++ 0 ++ 340 ++ 610 ++ ++ ++ ++ Form ++ ++ ++ ++ 3 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ ++ ++ QFrame::NoFrame ++ ++ ++ QFrame::Plain ++ ++ ++ ++ 3 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ ++ ++ do not translate ++ ++ ++ Qt::RichText ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ QFrame::NoFrame ++ ++ ++ QFrame::Plain ++ ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ Output filename suffix ++ ++ ++ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ _cut ++ ++ ++ Qt::AlignCenter ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Create overviews for result. ++ ++ ++ ++ ++ ++ ++ Qt::Vertical ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ ++ ++ ++ ++ 3 ++ ++ ++ ++ ++ false ++ ++ ++ Start ++ ++ ++ ++ :/icons/32x32/Apply.png:/icons/32x32/Apply.png ++ ++ ++ ++ ++ ++ ++ false ++ ++ ++ Cancel ++ ++ ++ ++ :/icons/32x32/Cancel.png:/icons/32x32/Cancel.png ++ ++ ++ ++ ++ ++ ++ For all files ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ 40 ++ 20 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ <b style='color: red;'>No "gdalwarp" found. Please check setup!</b> ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ <b style='color: red;'>No "gdaladdo" found. Please check setup!</b> ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ ++ CItemListWidget ++ QWidget ++
items/CItemListWidget.h
++ 1 ++
++ ++ CToolOverviewGroupBox ++ QGroupBox ++
tool/CToolOverviewGroupBox.h
++ 1 ++
++
++ ++ ++ ++ ++
+diff --git a/src/qmaptool/tool/IToolExport.ui b/src/qmaptool/tool/IToolExport.ui +new file mode 100644 +index 00000000..89e2cfd5 +--- /dev/null ++++ b/src/qmaptool/tool/IToolExport.ui +@@ -0,0 +1,206 @@ ++ ++ ++ IToolExport ++ ++ ++ ++ 0 ++ 0 ++ 332 ++ 346 ++ ++ ++ ++ Form ++ ++ ++ ++ 3 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ ++ ++ QFrame::NoFrame ++ ++ ++ QFrame::Plain ++ ++ ++ ++ 3 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ ++ ++ do not translate ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ do not translate ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ ++ Garmin BirdsEye (*.jnx) ++ ++ ++ ++ ++ TwoNav Raster (*.rmap) ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ not implemented yet ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Target File ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 3 ++ ++ ++ ++ ++ false ++ ++ ++ Start ++ ++ ++ ++ :/icons/32x32/Apply.png:/icons/32x32/Apply.png ++ ++ ++ ++ ++ ++ ++ false ++ ++ ++ Cancel ++ ++ ++ ++ :/icons/32x32/Cancel.png:/icons/32x32/Cancel.png ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ 40 ++ 20 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ <b style='color: red;'>No "qmt_map2jnx" found. Please check setup!</b> ++ ++ ++ ++ ++ ++ ++ ++ :/icons/32x32/PathBlue.png:/icons/32x32/PathBlue.png ++ ++ ++ Target Filename ++ ++ ++ ++ ++ ++ CToolExportJnx ++ QWidget ++
tool/export/CToolExportJnx.h
++ 1 ++
++ ++ CItemTreeWidget ++ QWidget ++
items/CItemTreeWidget.h
++ 1 ++
++
++ ++ ++ ++ ++
+diff --git a/src/qmaptool/tool/IToolGrid.ui b/src/qmaptool/tool/IToolGrid.ui +new file mode 100644 +index 00000000..3a79eaa5 +--- /dev/null ++++ b/src/qmaptool/tool/IToolGrid.ui +@@ -0,0 +1,158 @@ ++ ++ ++ IToolGrid ++ ++ ++ ++ 0 ++ 0 ++ 400 ++ 300 ++ ++ ++ ++ Form ++ ++ ++ ++ 6 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ ++ ++ ++ :/icons/32x32/GridTool.png ++ ++ ++ false ++ ++ ++ ++ ++ ++ ++ Grid Tool ++ ++ ++ ++ ++ ++ ++ ++ ++ do not translate ++ ++ ++ Qt::AutoText ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Qt::Vertical ++ ++ ++ ++ 20 ++ 226 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ false ++ ++ ++ Ok ++ ++ ++ ++ :/icons/32x32/Check.png:/icons/32x32/Check.png ++ ++ ++ ++ ++ ++ ++ Cancel ++ ++ ++ ++ :/icons/32x32/Cancel.png:/icons/32x32/Cancel.png ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ 40 ++ 20 ++ ++ ++ ++ ++ ++ ++ ++ Reset ++ ++ ++ ++ :/icons/32x32/Reload.png:/icons/32x32/Reload.png ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ COverlayGridTool ++ QWidget ++
overlay/COverlayGridTool.h
++ 1 ++
++
++ ++ ++ ++ ++
+diff --git a/src/qmaptool/tool/IToolGui.cpp b/src/qmaptool/tool/IToolGui.cpp +new file mode 100644 +index 00000000..fe3f5d8e +--- /dev/null ++++ b/src/qmaptool/tool/IToolGui.cpp +@@ -0,0 +1,111 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "canvas/IDrawContext.h" ++#include "items/CItemListWidget.h" ++#include "items/CItemMapLayer.h" ++#include "items/CItemTreeWidget.h" ++#include "items/IItem.h" ++#include "shell/CShell.h" ++#include "tool/IToolGui.h" ++ ++IToolGui::IToolGui(QWidget * parent) ++ : QWidget(parent) ++{ ++} ++ ++QString IToolGui::createTempFile(const QString& ext) ++{ ++ QTemporaryFile * tmpFile = new QTemporaryFile(QDir::temp().absoluteFilePath("QMapTool_XXXXXX." + ext)); ++ tmpFile->open(); ++ tmpFile->close(); ++ tmpFiles << tmpFile; ++ ++ return tmpFile->fileName(); ++} ++ ++bool IToolGui::finished(qint32 id) ++{ ++ if(id == jobId) ++ { ++ jobId = 0; ++ qDeleteAll(tmpFiles); ++ tmpFiles.clear(); ++ return true; ++ } ++ return false; ++} ++ ++ ++void IToolGui::start(CItemTreeWidget * itemTree) ++{ ++ QList cmds; ++ const int N = itemTree->topLevelItemCount(); ++ for(int n = 0; n < N; n++) ++ { ++ const CItemMapLayer * layer = dynamic_cast(itemTree->topLevelItem(n)); ++ if(layer == nullptr) ++ { ++ continue; ++ } ++ const int M = layer->childCount(); ++ for(int m = 0; m < M; m++) ++ { ++ IItem * item = dynamic_cast(layer->child(m)); ++ if(nullptr != item) ++ { ++ buildCmd(cmds, item); ++ } ++ } ++ } ++ ++ buildCmdFinal(cmds); ++ ++ jobId = CShell::self().execute(cmds); ++} ++ ++void IToolGui::start(CItemListWidget * itemList, bool allFiles) ++{ ++ QList cmds; ++ ++ if(allFiles) ++ { ++ const int N = itemList->count(); ++ for(int n = 0; n < N; n++) ++ { ++ const IItem * item = dynamic_cast(itemList->item(n)); ++ if(nullptr != item) ++ { ++ buildCmd(cmds, item); ++ } ++ } ++ } ++ else ++ { ++ const IItem * item = dynamic_cast(itemList->currentItem()); ++ if(nullptr != item) ++ { ++ buildCmd(cmds, item); ++ } ++ } ++ ++ buildCmdFinal(cmds); ++ ++ jobId = CShell::self().execute(cmds); ++} ++ +diff --git a/src/qmaptool/tool/IToolGui.h b/src/qmaptool/tool/IToolGui.h +new file mode 100644 +index 00000000..00432901 +--- /dev/null ++++ b/src/qmaptool/tool/IToolGui.h +@@ -0,0 +1,48 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef ITOOLGUI_H ++#define ITOOLGUI_H ++ ++#include ++ ++class CItemListWidget; ++class CItemTreeWidget; ++ ++class IToolGui : public QWidget ++{ ++ Q_OBJECT ++public: ++ IToolGui(QWidget * parent); ++ virtual ~IToolGui() = default; ++ ++ ++protected: ++ virtual void start(CItemListWidget * itemList, bool allFiles); ++ virtual void start(CItemTreeWidget * itemTree); ++ virtual bool finished(qint32 id); ++ virtual void buildCmd(QList& cmds, const IItem * iitem) = 0; ++ virtual void buildCmdFinal(QList& cmds){} ++ ++ QString createTempFile(const QString &ext); ++ qint32 jobId = 0; ++ QList tmpFiles; ++}; ++ ++#endif //ITOOLGUI_H ++ +diff --git a/src/qmaptool/tool/IToolOverviewGroupBox.ui b/src/qmaptool/tool/IToolOverviewGroupBox.ui +new file mode 100644 +index 00000000..c127a786 +--- /dev/null ++++ b/src/qmaptool/tool/IToolOverviewGroupBox.ui +@@ -0,0 +1,130 @@ ++ ++ ++ IToolOverviewGroupBox ++ ++ ++ ++ 0 ++ 0 ++ 400 ++ 96 ++ ++ ++ ++ GroupBox ++ ++ ++ false ++ ++ ++ true ++ ++ ++ true ++ ++ ++ ++ 3 ++ ++ ++ 9 ++ ++ ++ 3 ++ ++ ++ 9 ++ ++ ++ 3 ++ ++ ++ ++ ++ true ++ ++ ++ QFrame::NoFrame ++ ++ ++ QFrame::Raised ++ ++ ++ ++ 3 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ ++ ++ :2 ++ ++ ++ ++ ++ ++ ++ :4 ++ ++ ++ ++ ++ ++ ++ :8 ++ ++ ++ ++ ++ ++ ++ :16 ++ ++ ++ ++ ++ ++ ++ :32 ++ ++ ++ ++ ++ ++ ++ :64 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ true ++ ++ ++ Do not copy the overviews into the file itself. Add them as external file. ++ ++ ++ Overview as external file ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/src/qmaptool/tool/IToolPalettize.ui b/src/qmaptool/tool/IToolPalettize.ui +new file mode 100644 +index 00000000..b9131bde +--- /dev/null ++++ b/src/qmaptool/tool/IToolPalettize.ui +@@ -0,0 +1,269 @@ ++ ++ ++ IToolPalettize ++ ++ ++ ++ 0 ++ 0 ++ 400 ++ 399 ++ ++ ++ ++ Form ++ ++ ++ ++ 3 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ QFrame::NoFrame ++ ++ ++ QFrame::Plain ++ ++ ++ ++ 3 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ ++ ++ do not translate ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ do not translate ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ Single files, filename suffix ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ _8bit ++ ++ ++ Qt::AlignCenter ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Combined file, filename: ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Embed result into *.vrt file. ++ ++ ++ ++ ++ ++ ++ Create overviews for result. ++ ++ ++ ++ ++ ++ ++ Qt::Vertical ++ ++ ++ ++ 20 ++ 40 ++ ++ ++ ++ ++ ++ ++ ++ 3 ++ ++ ++ ++ ++ false ++ ++ ++ Start ++ ++ ++ ++ :/icons/32x32/Apply.png:/icons/32x32/Apply.png ++ ++ ++ ++ ++ ++ ++ false ++ ++ ++ Cancel ++ ++ ++ ++ :/icons/32x32/Cancel.png:/icons/32x32/Cancel.png ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ 40 ++ 20 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ <b style='color: red;'>No "gdaladdo" found. Please check setup!</b> ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ <b style='color: red;'>No "gdal_translate" found. Please check setup!</b> ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ <b style='color: red;'>No "qmt_rgb2pct" found. Please check setup!</b> ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ ++ :/icons/32x32/PathBlue.png:/icons/32x32/PathBlue.png ++ ++ ++ Select filename ++ ++ ++ ++ ++ ++ CItemListWidget ++ QWidget ++
items/CItemListWidget.h
++ 1 ++
++ ++ CToolOverviewGroupBox ++ QGroupBox ++
tool/CToolOverviewGroupBox.h
++ 1 ++
++
++ ++ ++ ++ ++
+diff --git a/src/qmaptool/tool/IToolRefMap.ui b/src/qmaptool/tool/IToolRefMap.ui +new file mode 100644 +index 00000000..9218f5fc +--- /dev/null ++++ b/src/qmaptool/tool/IToolRefMap.ui +@@ -0,0 +1,276 @@ ++ ++ ++ IToolRefMap ++ ++ ++ ++ 0 ++ 0 ++ 400 ++ 596 ++ ++ ++ ++ Form ++ ++ ++ ++ 3 ++ ++ ++ 0 ++ ++ ++ 3 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ ++ ++ QFrame::NoFrame ++ ++ ++ QFrame::Plain ++ ++ ++ ++ 3 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ ++ ++ do not translate ++ ++ ++ Qt::RichText ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ QFrame::NoFrame ++ ++ ++ QFrame::Plain ++ ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ Output filename suffix ++ ++ ++ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ _ref ++ ++ ++ Qt::AlignCenter ++ ++ ++ ++ ++ ++ ++ ++ ++ Embed result into *.vrt file. ++ ++ ++ ++ ++ ++ ++ Create overviews for result. ++ ++ ++ ++ ++ ++ ++ Qt::Vertical ++ ++ ++ ++ 20 ++ 40 ++ ++ ++ ++ ++ ++ ++ ++ 3 ++ ++ ++ ++ ++ false ++ ++ ++ Start ++ ++ ++ ++ :/icons/32x32/Apply.png:/icons/32x32/Apply.png ++ ++ ++ ++ ++ ++ ++ false ++ ++ ++ Cancel ++ ++ ++ ++ :/icons/32x32/Cancel.png:/icons/32x32/Cancel.png ++ ++ ++ ++ ++ ++ ++ For all files ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ 40 ++ 20 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ <b style='color: red;'>No "gdalwarp" found. Please check setup!</b> ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ <b style='color: red;'>No "gdal_translate" found. Please check setup!</b> ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ <b style='color: red;'>No "gdaladdo" found. Please check setup!</b> ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ ++ CItemListWidget ++ QWidget ++
items/CItemListWidget.h
++ 1 ++
++ ++ CToolOverviewGroupBox ++ QGroupBox ++
tool/CToolOverviewGroupBox.h
++ 1 ++
++
++ ++ ++ ++ ++
+diff --git a/src/qmaptool/tool/export/CToolExportJnx.cpp b/src/qmaptool/tool/export/CToolExportJnx.cpp +new file mode 100644 +index 00000000..5fbe48ce +--- /dev/null ++++ b/src/qmaptool/tool/export/CToolExportJnx.cpp +@@ -0,0 +1,28 @@ ++/********************************************************************************************** ++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "tool/export/CToolExportJnx.h" ++ ++#include ++ ++CToolExportJnx::CToolExportJnx() ++{ ++ setupUi(this); ++} ++ ++ +diff --git a/src/qmaptool/tool/export/CToolExportJnx.h b/src/qmaptool/tool/export/CToolExportJnx.h +new file mode 100644 +index 00000000..f1bb6619 +--- /dev/null ++++ b/src/qmaptool/tool/export/CToolExportJnx.h +@@ -0,0 +1,68 @@ ++/********************************************************************************************** ++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CTOOLEXPORTJNX_H ++#define CTOOLEXPORTJNX_H ++ ++#include "ui_IToolExportJnx.h" ++ ++class CToolExportJnx : public QWidget, private Ui::IToolExportJnx ++{ ++ Q_OBJECT ++public: ++ CToolExportJnx(); ++ virtual ~CToolExportJnx() = default; ++ ++ QString getProductName() const ++ { ++ return lineProductName->text(); ++ } ++ ++ QString getDescription() const ++ { ++ return lineDescription->text(); ++ } ++ ++ QString getCopyright() const ++ { ++ return lineCopyrightNotice->text(); ++ } ++ ++ QString getProductId() const ++ { ++ return QString::number(spinProductId->value()); ++ } ++ ++ QString getJpegQuality() const ++ { ++ return QString::number(spinJpegQuality->value()); ++ } ++ ++ QString getJpegSubsampling() const ++ { ++ return comboJpegSubSampling->currentText(); ++ } ++ ++ QString getZOrder() const ++ { ++ return QString::number(spinZOrder->value()); ++ } ++}; ++ ++#endif //CTOOLEXPORTJNX_H ++ +diff --git a/src/qmaptool/tool/export/IToolExportJnx.ui b/src/qmaptool/tool/export/IToolExportJnx.ui +new file mode 100644 +index 00000000..29ab36f6 +--- /dev/null ++++ b/src/qmaptool/tool/export/IToolExportJnx.ui +@@ -0,0 +1,224 @@ ++ ++ ++ IToolExportJnx ++ ++ ++ ++ 0 ++ 0 ++ 400 ++ 321 ++ ++ ++ ++ Form ++ ++ ++ ++ 3 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ ++ ++ BirdsEye ++ ++ ++ ++ 3 ++ ++ ++ 3 ++ ++ ++ 3 ++ ++ ++ ++ ++ Product ID ++ ++ ++ ++ ++ ++ ++ Copyright notice ++ ++ ++ ++ ++ ++ ++ None ++ ++ ++ ++ ++ ++ ++ Product name ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ BirdsEye ++ ++ ++ ++ ++ ++ ++ Description ++ ++ ++ ++ ++ ++ ++ None ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ JPEG ++ ++ ++ ++ 3 ++ ++ ++ 3 ++ ++ ++ 3 ++ ++ ++ ++ ++ 1 ++ ++ ++ 100 ++ ++ ++ 75 ++ ++ ++ ++ ++ ++ ++ Quality ++ ++ ++ ++ ++ ++ ++ Chroma subsampling ++ ++ ++ ++ ++ ++ ++ ++ 411 ++ ++ ++ ++ ++ 422 ++ ++ ++ ++ ++ 444 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Device ++ ++ ++ ++ 3 ++ ++ ++ 3 ++ ++ ++ 3 ++ ++ ++ ++ ++ Z-Order ++ ++ ++ ++ ++ ++ ++ 10 ++ ++ ++ 100 ++ ++ ++ 10 ++ ++ ++ 50 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Qt::Vertical ++ ++ ++ ++ 20 ++ 40 ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/src/qmaptool/units/CCoordFormatSetup.cpp b/src/qmaptool/units/CCoordFormatSetup.cpp +new file mode 100644 +index 00000000..69c7be3c +--- /dev/null ++++ b/src/qmaptool/units/CCoordFormatSetup.cpp +@@ -0,0 +1,67 @@ ++/********************************************************************************************** ++ Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "units/CCoordFormatSetup.h" ++#include "units/IUnit.h" ++ ++CCoordFormatSetup::CCoordFormatSetup(QWidget * parent) ++ : QDialog(parent) ++{ ++ setupUi(this); ++ ++ IUnit::coord_format_e coordFormat = IUnit::getCoordFormat(); ++ switch(coordFormat) ++ { ++ case IUnit::eCoordFormat1: ++ radioFormat1->setChecked(true); ++ break; ++ ++ case IUnit::eCoordFormat2: ++ radioFormat2->setChecked(true); ++ break; ++ ++ case IUnit::eCoordFormat3: ++ radioFormat3->setChecked(true); ++ break; ++ } ++} ++ ++CCoordFormatSetup::~CCoordFormatSetup() ++{ ++} ++ ++void CCoordFormatSetup::accept() ++{ ++ IUnit::coord_format_e coordFormat = IUnit::eCoordFormat1; ++ ++ if(radioFormat1->isChecked()) ++ { ++ coordFormat = IUnit::eCoordFormat1; ++ } ++ else if(radioFormat2->isChecked()) ++ { ++ coordFormat = IUnit::eCoordFormat2; ++ } ++ else if(radioFormat3->isChecked()) ++ { ++ coordFormat = IUnit::eCoordFormat3; ++ } ++ ++ IUnit::setCoordFormat(coordFormat); ++ QDialog::accept(); ++} +diff --git a/src/qmaptool/units/CCoordFormatSetup.h b/src/qmaptool/units/CCoordFormatSetup.h +new file mode 100644 +index 00000000..0510ae25 +--- /dev/null ++++ b/src/qmaptool/units/CCoordFormatSetup.h +@@ -0,0 +1,37 @@ ++/********************************************************************************************** ++ Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CCOORDFORMATSETUP_H ++#define CCOORDFORMATSETUP_H ++ ++#include "ui_ICoordFormatSetup.h" ++#include ++ ++class CCoordFormatSetup : public QDialog, private Ui::ICoordFormatSetup ++{ ++ Q_OBJECT ++public: ++ CCoordFormatSetup(QWidget * parent); ++ virtual ~CCoordFormatSetup(); ++ ++public slots: ++ void accept() override; ++}; ++ ++#endif //CCOORDFORMATSETUP_H ++ +diff --git a/src/qmaptool/units/CTimeZoneSetup.cpp b/src/qmaptool/units/CTimeZoneSetup.cpp +new file mode 100644 +index 00000000..d6f849bd +--- /dev/null ++++ b/src/qmaptool/units/CTimeZoneSetup.cpp +@@ -0,0 +1,105 @@ ++/********************************************************************************************** ++ Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "units/CTimeZoneSetup.h" ++#include "units/IUnit.h" ++ ++CTimeZoneSetup::CTimeZoneSetup(QWidget *parent) ++ : QDialog(parent) ++{ ++ setupUi(this); ++ ++ QByteArray zone; ++ IUnit::tz_mode_e mode; ++ bool useShortFormat; ++ ++ IUnit::getTimeZoneSetup(mode, zone, useShortFormat); ++ ++ switch(mode) ++ { ++ case IUnit::eTZUtc: ++ radioUtc->setChecked(true); ++ break; ++ ++ case IUnit::eTZLocal: ++ radioLocal->setChecked(true); ++ break; ++ ++ case IUnit::eTZAuto: ++ radioAutomatic->setChecked(true); ++ break; ++ ++ case IUnit::eTZSelected: ++ radioSelected->setChecked(true); ++ break; ++ } ++ ++ const char ** tz = IUnit::tblTimezone; ++ while(*tz) ++ { ++ comboTimeZone->addItem(*tz); ++ tz++; ++ } ++ ++ if(useShortFormat) ++ { ++ radioShortFormat->setChecked(true); ++ } ++ else ++ { ++ radioLongFormat->setChecked(true); ++ } ++ ++ comboTimeZone->setCurrentIndex(comboTimeZone->findText(QString(zone))); ++} ++ ++CTimeZoneSetup::~CTimeZoneSetup() ++{ ++} ++ ++void CTimeZoneSetup::accept() ++{ ++ QByteArray zone = comboTimeZone->currentText().toLatin1(); ++ IUnit::tz_mode_e mode = IUnit::eTZUtc; ++ bool useShortFormat = false; ++ ++ if(radioUtc->isChecked()) ++ { ++ mode = IUnit::eTZUtc; ++ } ++ else if(radioLocal->isChecked()) ++ { ++ mode = IUnit::eTZLocal; ++ } ++ else if(radioAutomatic->isChecked()) ++ { ++ mode = IUnit::eTZAuto; ++ } ++ else if(radioSelected->isChecked()) ++ { ++ mode = IUnit::eTZSelected; ++ } ++ ++ if(radioShortFormat->isChecked()) ++ { ++ useShortFormat = true; ++ } ++ ++ IUnit::setTimeZoneSetup(mode, zone, useShortFormat); ++ QDialog::accept(); ++} +diff --git a/src/qmaptool/units/CTimeZoneSetup.h b/src/qmaptool/units/CTimeZoneSetup.h +new file mode 100644 +index 00000000..aa06ad85 +--- /dev/null ++++ b/src/qmaptool/units/CTimeZoneSetup.h +@@ -0,0 +1,36 @@ ++/********************************************************************************************** ++ Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CTIMEZONESETUP_H ++#define CTIMEZONESETUP_H ++ ++#include "ui_ITimeZoneSetup.h" ++#include ++ ++class CTimeZoneSetup : public QDialog, private Ui::ITimeZoneSetup ++{ ++public: ++ CTimeZoneSetup(QWidget * parent); ++ virtual ~CTimeZoneSetup(); ++ ++public slots: ++ void accept() override; ++}; ++ ++#endif //CTIMEZONESETUP_H ++ +diff --git a/src/qmaptool/units/CUnitImperial.cpp b/src/qmaptool/units/CUnitImperial.cpp +new file mode 100644 +index 00000000..f38c73fb +--- /dev/null ++++ b/src/qmaptool/units/CUnitImperial.cpp +@@ -0,0 +1,113 @@ ++/********************************************************************************************** ++ Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA ++ ++**********************************************************************************************/ ++ ++#include "units/CUnitImperial.h" ++ ++const qreal CUnitImperial::footPerMeter = 3.28084; ++const qreal CUnitImperial::milePerMeter = 0.6213699E-3; ++const qreal CUnitImperial::meterPerSecToMilePerHour = 2.23693164; ++ ++CUnitImperial::CUnitImperial(QObject * parent) ++ : IUnit(eTypeImperial, "ft", footPerMeter, "ml/h", meterPerSecToMilePerHour, parent) ++{ ++} ++ ++ ++void CUnitImperial::meter2elevation(qreal meter, QString& val, QString& unit) const /* override */ ++{ ++ if(meter == NOFLOAT) ++ { ++ val = "-"; ++ unit = ""; ++ } ++ else ++ { ++ val.sprintf("%1.0f", meter * footPerMeter); ++ unit = "ft"; ++ } ++} ++ ++ ++void CUnitImperial::meter2distance(qreal meter, QString& val, QString& unit) const /* override */ ++{ ++ if(meter == NOFLOAT) ++ { ++ val = "-"; ++ unit = ""; ++ } ++ else if(meter < 10) ++ { ++ val.sprintf("%1.1f", meter * footPerMeter); ++ unit = "ft"; ++ } ++ else if(meter < 1600) ++ { ++ val.sprintf("%1.0f", meter * footPerMeter); ++ unit = "ft"; ++ } ++ else if(meter < 16000) ++ { ++ val.sprintf("%1.2f", meter * milePerMeter); ++ unit = "ml"; ++ } ++ else if(meter < 32000) ++ { ++ val.sprintf("%1.1f", meter * milePerMeter); ++ unit = "ml"; ++ } ++ else ++ { ++ val.sprintf("%1.0f", meter * milePerMeter); ++ unit = "ml"; ++ } ++} ++ ++void CUnitImperial::meter2area(qreal meter, QString& val, QString& unit) const /* override */ ++{ ++ if(meter == NOFLOAT) ++ { ++ val = "-"; ++ unit = ""; ++ } ++ else ++ { ++ val.sprintf("%1.2f", meter / (1/milePerMeter * 1/milePerMeter)); ++ unit = "ml²"; ++ } ++} ++ ++qreal CUnitImperial::elevation2meter(const QString& val) const /* override */ ++{ ++ return val.toDouble() / footPerMeter; ++} ++ ++void CUnitImperial::meter2unit(qreal meter, qreal& scale, QString& unit) const ++{ ++ if(meter > 1600) ++ { ++ scale = milePerMeter; ++ unit = "ml"; ++ } ++ else ++ { ++ scale = footPerMeter; ++ unit = "ft"; ++ } ++} ++ +diff --git a/src/qmaptool/units/CUnitImperial.h b/src/qmaptool/units/CUnitImperial.h +new file mode 100644 +index 00000000..e400159d +--- /dev/null ++++ b/src/qmaptool/units/CUnitImperial.h +@@ -0,0 +1,41 @@ ++/********************************************************************************************** ++ Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA ++ ++**********************************************************************************************/ ++#ifndef CUNITIMPERIAL_H ++#define CUNITIMPERIAL_H ++ ++#include "IUnit.h" ++ ++class CUnitImperial : public IUnit ++{ ++public: ++ CUnitImperial(QObject * parent); ++ virtual ~CUnitImperial() = default; ++ ++ void meter2elevation(qreal meter, QString& val, QString& unit) const override; ++ void meter2distance(qreal meter, QString& val, QString& unit) const override; ++ void meter2area(qreal meter, QString& val, QString& unit) const override; ++ qreal elevation2meter(const QString& val) const override; ++ void meter2unit(qreal meter, qreal& scale, QString& unit) const override; ++ ++private: ++ static const qreal footPerMeter; ++ static const qreal milePerMeter; ++ static const qreal meterPerSecToMilePerHour; ++}; ++#endif //CUNITIMPERIAL_H +diff --git a/src/qmaptool/units/CUnitMetric.cpp b/src/qmaptool/units/CUnitMetric.cpp +new file mode 100644 +index 00000000..4398eef2 +--- /dev/null ++++ b/src/qmaptool/units/CUnitMetric.cpp +@@ -0,0 +1,132 @@ ++/********************************************************************************************** ++ Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA ++ ++**********************************************************************************************/ ++#include "units/CUnitMetric.h" ++ ++CUnitMetric::CUnitMetric(QObject * parent) ++ : IUnit(eTypeMetric, "m", 1.0, "km/h", 3.6, parent) ++{ ++} ++ ++ ++void CUnitMetric::meter2elevation(qreal meter, QString& val, QString& unit) const /* override */ ++{ ++ if(meter == NOFLOAT || meter == NOINT) ++ { ++ val = "-"; ++ unit = ""; ++ } ++ else ++ { ++ val.sprintf("%1.0f", meter); ++ unit = "m"; ++ } ++} ++ ++ ++void CUnitMetric::meter2distance(qreal meter, QString& val, QString& unit) const /* override */ ++{ ++ if(meter == NOFLOAT) ++ { ++ val = "-"; ++ unit = ""; ++ } ++ else if(meter < 10) ++ { ++ val.sprintf("%1.1f", meter); ++ unit = "m"; ++ } ++ else if(meter < 1000) ++ { ++ val.sprintf("%1.0f", meter); ++ unit = "m"; ++ } ++ else if(meter < 10000) ++ { ++ val.sprintf("%1.2f", meter / 1000); ++ unit = "km"; ++ } ++ else if(meter < 20000) ++ { ++ val.sprintf("%1.1f", meter / 1000); ++ unit = "km"; ++ } ++ else ++ { ++ val.sprintf("%1.0f", meter / 1000); ++ unit = "km"; ++ } ++} ++ ++ ++void CUnitMetric::meter2speed(qreal meter, QString& val, QString& unit) const /* override */ ++{ ++ if(meter == NOFLOAT) ++ { ++ val = "-"; ++ unit = ""; ++ } ++ else if (meter < 0.27) ++ { ++ val.sprintf("%1.0f",meter * speedfactor * 1000); ++ unit = "m/h"; ++ } ++ else if (meter < 10.0) ++ { ++ val.sprintf("%1.1f",meter * speedfactor); ++ unit = speedunit; ++ } ++ else ++ { ++ val.sprintf("%1.0f",meter * speedfactor); ++ unit = speedunit; ++ } ++} ++ ++void CUnitMetric::meter2area(qreal meter, QString& val, QString& unit) const /* override */ ++{ ++ if(meter == NOFLOAT) ++ { ++ val = "-"; ++ unit = ""; ++ } ++ else ++ { ++ val.sprintf("%1.2f", meter / 1000000); ++ unit = "km²"; ++ } ++} ++ ++qreal CUnitMetric::elevation2meter(const QString& val) const /* override */ ++{ ++ return val.toDouble(); ++} ++ ++void CUnitMetric::meter2unit(qreal meter, qreal& scale, QString& unit) const ++{ ++ if(meter > 1000) ++ { ++ scale = 0.001; ++ unit = "km"; ++ } ++ else ++ { ++ scale = 1.0; ++ unit = "m"; ++ } ++} +diff --git a/src/qmaptool/units/CUnitMetric.h b/src/qmaptool/units/CUnitMetric.h +new file mode 100644 +index 00000000..3f8c74a6 +--- /dev/null ++++ b/src/qmaptool/units/CUnitMetric.h +@@ -0,0 +1,37 @@ ++/********************************************************************************************** ++ Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA ++ ++**********************************************************************************************/ ++#ifndef CUNITMETRIC_H ++#define CUNITMETRIC_H ++ ++#include "IUnit.h" ++ ++class CUnitMetric : public IUnit ++{ ++public: ++ CUnitMetric(QObject * parent); ++ virtual ~CUnitMetric() = default; ++ ++ void meter2elevation(qreal meter, QString& val, QString& unit) const override; ++ void meter2distance(qreal meter, QString& val, QString& unit) const override; ++ void meter2speed(qreal meter, QString& val, QString& unit) const override; ++ void meter2area(qreal meter, QString& val, QString& unit) const override; ++ qreal elevation2meter(const QString& val) const override; ++ void meter2unit(qreal meter, qreal& scale, QString& unit) const override; ++}; ++#endif // CUNITMETRIC_H +diff --git a/src/qmaptool/units/CUnitNautic.cpp b/src/qmaptool/units/CUnitNautic.cpp +new file mode 100644 +index 00000000..d4f2a995 +--- /dev/null ++++ b/src/qmaptool/units/CUnitNautic.cpp +@@ -0,0 +1,96 @@ ++/********************************************************************************************** ++ Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA ++ ++**********************************************************************************************/ ++ ++#include "units/CUnitNautic.h" ++ ++CUnitNautic::CUnitNautic(QObject * parent) ++ : IUnit(eTypeNautic, "nm", 0.00053989, "nm/h", 1.94361780, parent) ++{ ++} ++ ++ ++void CUnitNautic::meter2elevation(qreal meter, QString& val, QString& unit) const /* override */ ++{ ++ if(meter == NOFLOAT) ++ { ++ val = "-"; ++ unit = ""; ++ } ++ else ++ { ++ val.sprintf("%1.0f", meter); ++ unit = "m"; ++ } ++} ++ ++ ++void CUnitNautic::meter2distance(qreal meter, QString& val, QString& unit) const /* override */ ++{ ++ if(meter == NOFLOAT) ++ { ++ val = "-"; ++ unit = ""; ++ } ++ else ++ { ++ val.sprintf("%1.2f", meter * basefactor); ++ unit = baseunit; ++ } ++} ++ ++ ++void CUnitNautic::meter2speed(qreal meter, QString& val, QString& unit) const /* override */ ++{ ++ if(meter == NOFLOAT) ++ { ++ val = "-"; ++ unit = ""; ++ } ++ else ++ { ++ val.sprintf("%1.2f",meter * speedfactor); ++ unit = speedunit; ++ } ++} ++ ++void CUnitNautic::meter2area(qreal meter, QString& val, QString& unit) const /* override */ ++{ ++ if(meter == NOFLOAT) ++ { ++ val = "-"; ++ unit = ""; ++ } ++ else ++ { ++ val.sprintf("%1.2f", meter / (1852 * 1852)); ++ unit = "nm²"; ++ } ++} ++ ++ ++qreal CUnitNautic::elevation2meter(const QString& val) const /* override */ ++{ ++ return val.toDouble(); ++} ++ ++void CUnitNautic::meter2unit(qreal meter, qreal& scale, QString& unit) const ++{ ++ scale = basefactor; ++ unit = "nm"; ++} +diff --git a/src/qmaptool/units/CUnitNautic.h b/src/qmaptool/units/CUnitNautic.h +new file mode 100644 +index 00000000..d3afc9e6 +--- /dev/null ++++ b/src/qmaptool/units/CUnitNautic.h +@@ -0,0 +1,37 @@ ++/********************************************************************************************** ++ Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA ++ ++**********************************************************************************************/ ++#ifndef CUNITNAUTIC_H ++#define CUNITNAUTIC_H ++ ++#include "IUnit.h" ++ ++class CUnitNautic : public IUnit ++{ ++public: ++ CUnitNautic(QObject * parent); ++ virtual ~CUnitNautic() = default; ++ ++ void meter2elevation(qreal meter, QString& val, QString& unit) const override; ++ void meter2distance(qreal meter, QString& val, QString& unit) const override; ++ void meter2speed(qreal meter, QString& val, QString& unit) const override; ++ void meter2area(qreal meter, QString& val, QString& unit) const override; ++ qreal elevation2meter(const QString& val) const override; ++ void meter2unit(qreal meter, qreal& scale, QString& unit) const override; ++}; ++#endif //CUNITNAUTIC_H +diff --git a/src/qmaptool/units/CUnitsSetup.cpp b/src/qmaptool/units/CUnitsSetup.cpp +new file mode 100644 +index 00000000..8d083f69 +--- /dev/null ++++ b/src/qmaptool/units/CUnitsSetup.cpp +@@ -0,0 +1,59 @@ ++/********************************************************************************************** ++ Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "CMainWindow.h" ++#include "units/CUnitsSetup.h" ++#include "units/IUnit.h" ++ ++CUnitsSetup::CUnitsSetup(QWidget *parent) ++ : QDialog(parent) ++{ ++ setupUi(this); ++ ++ switch(IUnit::self().type) ++ { ++ case IUnit::eTypeMetric: ++ radioMetric->setChecked(true); ++ break; ++ ++ case IUnit::eTypeImperial: ++ radioImperial->setChecked(true); ++ break; ++ ++ case IUnit::eTypeNautic: ++ radioNautic->setChecked(true); ++ break; ++ } ++} ++ ++void CUnitsSetup::accept() ++{ ++ if(radioMetric->isChecked()) ++ { ++ IUnit::setUnitType(IUnit::eTypeMetric, &CMainWindow::self()); ++ } ++ else if(radioImperial->isChecked()) ++ { ++ IUnit::setUnitType(IUnit::eTypeImperial, &CMainWindow::self()); ++ } ++ else if(radioNautic->isChecked()) ++ { ++ IUnit::setUnitType(IUnit::eTypeNautic, &CMainWindow::self()); ++ } ++ QDialog::accept(); ++} +diff --git a/src/qmaptool/units/CUnitsSetup.h b/src/qmaptool/units/CUnitsSetup.h +new file mode 100644 +index 00000000..765f7969 +--- /dev/null ++++ b/src/qmaptool/units/CUnitsSetup.h +@@ -0,0 +1,35 @@ ++/********************************************************************************************** ++ Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++#ifndef CUNITSSETUP_H ++#define CUNITSSETUP_H ++ ++#include "ui_IUnitsSetup.h" ++#include ++ ++class CUnitsSetup : public QDialog, private Ui::IUnitsSetup ++{ ++public: ++ CUnitsSetup(QWidget * parent); ++ virtual ~CUnitsSetup() = default; ++ ++public slots: ++ void accept() override; ++}; ++ ++#endif //CUNITSSETUP_H ++ +diff --git a/src/qmaptool/units/ICoordFormatSetup.ui b/src/qmaptool/units/ICoordFormatSetup.ui +new file mode 100644 +index 00000000..df39ec7e +--- /dev/null ++++ b/src/qmaptool/units/ICoordFormatSetup.ui +@@ -0,0 +1,125 @@ ++ ++ ++ ICoordFormatSetup ++ ++ ++ ++ 0 ++ 0 ++ 512 ++ 144 ++ ++ ++ ++ Coordinate Format... ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ N48° 53' 39.6" E13° 31' 6.78" ++ ++ ++ ++ ++ ++ ++ N48.8943° E013.51855° ++ ++ ++ ++ ++ ++ ++ N48° 53.660 E013° 31.113 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ <b>Note:</b> For some GUI elements changing the units will not take effect until you restart QMapTool. ++ ++ ++ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ ++ ++ Qt::Vertical ++ ++ ++ ++ 20 ++ 40 ++ ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ QDialogButtonBox::Cancel|QDialogButtonBox::Ok ++ ++ ++ ++ ++ ++ ++ ++ ++ buttonBox ++ accepted() ++ ICoordFormatSetup ++ accept() ++ ++ ++ 248 ++ 254 ++ ++ ++ 157 ++ 274 ++ ++ ++ ++ ++ buttonBox ++ rejected() ++ ICoordFormatSetup ++ reject() ++ ++ ++ 316 ++ 260 ++ ++ ++ 286 ++ 274 ++ ++ ++ ++ ++ +diff --git a/src/qmaptool/units/ITimeZoneSetup.ui b/src/qmaptool/units/ITimeZoneSetup.ui +new file mode 100644 +index 00000000..2313e881 +--- /dev/null ++++ b/src/qmaptool/units/ITimeZoneSetup.ui +@@ -0,0 +1,182 @@ ++ ++ ++ ITimeZoneSetup ++ ++ ++ ++ 0 ++ 0 ++ 398 ++ 106 ++ ++ ++ ++ Setup Time Zone ... ++ ++ ++ ++ ++ ++ ++ ++ UTC ++ ++ ++ buttonGroup ++ ++ ++ ++ ++ ++ ++ Local ++ ++ ++ buttonGroup ++ ++ ++ ++ ++ ++ ++ Automatic ++ ++ ++ buttonGroup ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ ++ ++ ++ buttonGroup ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Print date/time in ++ ++ ++ ++ ++ ++ ++ long format, or ++ ++ ++ buttonGroup_2 ++ ++ ++ ++ ++ ++ ++ short format ++ ++ ++ buttonGroup_2 ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ 40 ++ 20 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Qt::Vertical ++ ++ ++ ++ 20 ++ 40 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ QDialogButtonBox::Cancel|QDialogButtonBox::Ok ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ buttonBox ++ accepted() ++ ITimeZoneSetup ++ accept() ++ ++ ++ 248 ++ 254 ++ ++ ++ 157 ++ 274 ++ ++ ++ ++ ++ buttonBox ++ rejected() ++ ITimeZoneSetup ++ reject() ++ ++ ++ 316 ++ 260 ++ ++ ++ 286 ++ 274 ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/src/qmaptool/units/IUnit.cpp b/src/qmaptool/units/IUnit.cpp +new file mode 100644 +index 00000000..d266c6d0 +--- /dev/null ++++ b/src/qmaptool/units/IUnit.cpp +@@ -0,0 +1,776 @@ ++/********************************************************************************************** ++ Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA ++ ++**********************************************************************************************/ ++#include "CMainWindow.h" ++#include "GeoMath.h" ++#include "units/CUnitImperial.h" ++#include "units/CUnitMetric.h" ++#include "units/CUnitNautic.h" ++ ++#include ++#include ++const IUnit * IUnit::m_self = nullptr; ++ ++const QPointF NOPOINTF(NOFLOAT, NOFLOAT); ++const QPoint NOPOINT (NOINT, NOINT); ++ ++IUnit::tz_mode_e IUnit::timeZoneMode = IUnit::eTZUtc; ++IUnit::coord_format_e IUnit::coordFormat = IUnit::eCoordFormat1; ++QByteArray IUnit::timeZone = "UTC"; ++bool IUnit::useShortFormat = false; ++ ++const char * IUnit::tblTimezone[] = ++{ ++ "Africa/Abidjan", ++ "Africa/Accra", ++ "Africa/Addis_Ababa", ++ "Africa/Algiers", ++ "Africa/Asmara", ++ "Africa/Bamako", ++ "Africa/Bangui", ++ "Africa/Banjul", ++ "Africa/Bissau", ++ "Africa/Blantyre", ++ "Africa/Brazzaville", ++ "Africa/Bujumbura", ++ "Africa/Cairo", ++ "Africa/Casablanca", ++ "Africa/Conakry", ++ "Africa/Dakar", ++ "Africa/Dar_es_Salaam", ++ "Africa/Djibouti", ++ "Africa/Douala", ++ "Africa/El_Aaiun", ++ "Africa/Freetown", ++ "Africa/Gaborone", ++ "Africa/Harare", ++ "Africa/Johannesburg", ++ "Africa/Kampala", ++ "Africa/Khartoum", ++ "Africa/Kigali", ++ "Africa/Kinshasa", ++ "Africa/Lagos", ++ "Africa/Libreville", ++ "Africa/Lome", ++ "Africa/Luanda", ++ "Africa/Lubumbashi", ++ "Africa/Lusaka", ++ "Africa/Malabo", ++ "Africa/Maputo", ++ "Africa/Maseru", ++ "Africa/Mbabane", ++ "Africa/Mogadishu", ++ "Africa/Monrovia", ++ "Africa/Nairobi", ++ "Africa/Ndjamena", ++ "Africa/Niamey", ++ "Africa/Nouakchott", ++ "Africa/Ouagadougou", ++ "Africa/Porto-Novo", ++ "Africa/Sao_Tome", ++ "Africa/Tripoli", ++ "Africa/Tunis", ++ "Africa/Windhoek", ++ "America/Adak", ++ "America/Anguilla", ++ "America/Antigua", ++ "America/Araguaina", ++ "America/Argentina/Buenos_Aires", ++ "America/Argentina/Catamarca", ++ "America/Argentina/Cordoba", ++ "America/Argentina/Jujuy", ++ "America/Argentina/La_Rioja", ++ "America/Argentina/Mendoza", ++ "America/Argentina/Rio_Gallegos", ++ "America/Argentina/San_Juan", ++ "America/Argentina/San_Luis", ++ "America/Argentina/Tucuman", ++ "America/Argentina/Ushuaia", ++ "America/Aruba", ++ "America/Asuncion", ++ "America/Atikokan", ++ "America/Bahia", ++ "America/Barbados", ++ "America/Belem", ++ "America/Belize", ++ "America/Blanc-Sablon", ++ "America/Boa_Vista", ++ "America/Bogota", ++ "America/Boise", ++ "America/Cambridge_Bay", ++ "America/Campo_Grande", ++ "America/Cancun", ++ "America/Caracas", ++ "America/Cayenne", ++ "America/Cayman", ++ "America/Chicago", ++ "America/Chihuahua", ++ "America/Coral_Harbour", ++ "America/Costa_Rica", ++ "America/Cuiaba", ++ "America/Curacao", ++ "America/Dawson", ++ "America/Dawson_Creek", ++ "America/Denver", ++ "America/Dominica", ++ "America/Edmonton", ++ "America/Eirunepe", ++ "America/El_Salvador", ++ "America/Fortaleza", ++ "America/Glace_Bay", ++ "America/Goose_Bay", ++ "America/Grand_Turk", ++ "America/Grenada", ++ "America/Guadeloupe", ++ "America/Guatemala", ++ "America/Guayaquil", ++ "America/Guyana", ++ "America/Halifax", ++ "America/Havana", ++ "America/Hermosillo", ++ "America/Indiana/Indianapolis", ++ "America/Indiana/Knox", ++ "America/Indiana/Marengo", ++ "America/Indiana/Petersburg", ++ "America/Indiana/Vevay", ++ "America/Indiana/Vincennes", ++ "America/Indiana/Winamac", ++ "America/Inuvik", ++ "America/Iqaluit", ++ "America/Jamaica", ++ "America/Juneau", ++ "America/Kentucky/Louisville", ++ "America/Kentucky/Monticello", ++ "America/La_Paz", ++ "America/Lima", ++ "America/Los_Angeles", ++ "America/Maceio", ++ "America/Managua", ++ "America/Manaus", ++ "America/Marigot", ++ "America/Martinique", ++ "America/Mazatlan", ++ "America/Menominee", ++ "America/Merida", ++ "America/Mexico_City", ++ "America/Miquelon", ++ "America/Moncton", ++ "America/Monterrey", ++ "America/Montevideo", ++ "America/Montreal", ++ "America/Montserrat", ++ "America/Nassau", ++ "America/New_York", ++ "America/Nipigon", ++ "America/Noronha", ++ "America/North_Dakota/Center", ++ "America/North_Dakota/Salem", ++ "America/Panama", ++ "America/Pangnirtung", ++ "America/Paramaribo", ++ "America/Phoenix", ++ "America/Port-au-Prince", ++ "America/Port_of_Spain", ++ "America/Porto_Velho", ++ "America/Puerto_Rico", ++ "America/Rainy_River", ++ "America/Rankin_Inlet", ++ "America/Recife", ++ "America/Regina", ++ "America/Resolute", ++ "America/Rio_Branco", ++ "America/Santarem", ++ "America/Santiago", ++ "America/Santo_Domingo", ++ "America/Sao_Paulo", ++ "America/St_Barthelemy", ++ "America/St_Johns", ++ "America/St_Kitts", ++ "America/St_Lucia", ++ "America/St_Thomas", ++ "America/St_Vincent", ++ "America/Tegucigalpa", ++ "America/Thunder_Bay", ++ "America/Tijuana", ++ "America/Toronto", ++ "America/Tortola", ++ "America/Vancouver", ++ "America/Whitehorse", ++ "America/Winnipeg", ++ "America/Yellowknife", ++ "Ameriica/Swift_Current", ++ "Arctic/Longyearbyen", ++ "Asia/Aden", ++ "Asia/Almaty", ++ "Asia/Amman", ++ "Asia/Anadyr", ++ "Asia/Aqtau", ++ "Asia/Aqtobe", ++ "Asia/Ashgabat", ++ "Asia/Baghdad", ++ "Asia/Bahrain", ++ "Asia/Baku", ++ "Asia/Bangkok", ++ "Asia/Beirut", ++ "Asia/Bishkek", ++ "Asia/Brunei", ++ "Asia/Choibalsan", ++ "Asia/Chongqing", ++ "Asia/Colombo", ++ "Asia/Damascus", ++ "Asia/Dhaka", ++ "Asia/Dili", ++ "Asia/Dubai", ++ "Asia/Dushanbe", ++ "Asia/Gaza", ++ "Asia/Harbin", ++ "Asia/Ho_Chi_Minh", ++ "Asia/Hong_Kong", ++ "Asia/Hovd", ++ "Asia/Irkutsk", ++ "Asia/Jakarta", ++ "Asia/Jayapura", ++ "Asia/Jerusalem", ++ "Asia/Kabul", ++ "Asia/Kamchatka", ++ "Asia/Karachi", ++ "Asia/Kashgar", ++ "Asia/Katmandu", ++ "Asia/Kolkata", ++ "Asia/Krasnoyarsk", ++ "Asia/Kuala_Lumpur", ++ "Asia/Kuching", ++ "Asia/Kuwait", ++ "Asia/Macau", ++ "Asia/Magadan", ++ "Asia/Makassar", ++ "Asia/Manila", ++ "Asia/Muscat", ++ "Asia/Nicosia", ++ "Asia/Novosibirsk", ++ "Asia/Omsk", ++ "Asia/Oral", ++ "Asia/Phnom_Penh", ++ "Asia/Pontianak", ++ "Asia/Pyongyang", ++ "Asia/Qatar", ++ "Asia/Qyzylorda", ++ "Asia/Rangoon", ++ "Asia/Riyadh", ++ "Asia/Sakhalin", ++ "Asia/Samarkand", ++ "Asia/Seoul", ++ "Asia/Shanghai", ++ "Asia/Singapore", ++ "Asia/Taipei", ++ "Asia/Tashkent", ++ "Asia/Tbilisi", ++ "Asia/Tehran", ++ "Asia/Thimphu", ++ "Asia/Tokyo", ++ "Asia/Ulaanbaatar", ++ "Asia/Urumqi", ++ "Asia/Vientiane", ++ "Asia/Vladivostok", ++ "Asia/Yakutsk", ++ "Asia/Yekaterinburg", ++ "Asia/Yerevan", ++ "Atlantic/Azores", ++ "Atlantic/Bermuda", ++ "Atlantic/Canary", ++ "Atlantic/Cape_Verde", ++ "Atlantic/Faroe", ++ "Atlantic/Madeira", ++ "Atlantic/Reykjavik", ++ "Atlantic/South_Georgia", ++ "Atlantic/St_Helena", ++ "Atlantic/Stanley", ++ "Australia/Adelaide", ++ "Australia/Brisbane", ++ "Australia/Broken_Hill", ++ "Australia/Currie", ++ "Australia/Darwin", ++ "Australia/Eucla", ++ "Australia/Hobart", ++ "Australia/Lindeman", ++ "Australia/Lord_Howe", ++ "Australia/Melbourne", ++ "Australia/Perth", ++ "Australia/Sydney", ++ "Europe/Amsterdam", ++ "Europe/Andorra", ++ "Europe/Athens", ++ "Europe/Belgrade", ++ "Europe/Berlin", ++ "Europe/Bratislava", ++ "Europe/Brussels", ++ "Europe/Bucharest", ++ "Europe/Budapest", ++ "Europe/Chisinau", ++ "Europe/Copenhagen", ++ "Europe/Dublin", ++ "Europe/Gibraltar", ++ "Europe/Guernsey", ++ "Europe/Helsinki", ++ "Europe/Isle_of_Man", ++ "Europe/Istanbul", ++ "Europe/Jersey", ++ "Europe/Kaliningrad", ++ "Europe/Kiev", ++ "Europe/Lisbon", ++ "Europe/Ljubljana", ++ "Europe/London", ++ "Europe/Luxembourg", ++ "Europe/Madrid", ++ "Europe/Malta", ++ "Europe/Marienhamn", ++ "Europe/Minsk", ++ "Europe/Monaco", ++ "Europe/Moscow", ++ "Europe/Oslo", ++ "Europe/Paris", ++ "Europe/Podgorica", ++ "Europe/Prague", ++ "Europe/Riga", ++ "Europe/Rome", ++ "Europe/Samara", ++ "Europe/San_Marino", ++ "Europe/Sarajevo", ++ "Europe/Simferopol", ++ "Europe/Skopje", ++ "Europe/Sofia", ++ "Europe/Stockholm", ++ "Europe/Tallinn", ++ "Europe/Tirane", ++ "Europe/Uzhgorod", ++ "Europe/Vaduz", ++ "Europe/Vatican", ++ "Europe/Vienna", ++ "Europe/Vilnius", ++ "Europe/Volgograd", ++ "Europe/Warsaw", ++ "Europe/Zagreb", ++ "Europe/Zaporozhye", ++ "Europe/Zurich", ++ "Indian/Antananarivo", ++ "Indian/Chagos", ++ "Indian/Christmas", ++ "Indian/Cocos", ++ "Indian/Comoro", ++ "Indian/Kerguelen", ++ "Indian/Mahe", ++ "Indian/Maldives", ++ "Indian/Mauritius", ++ "Indian/Mayotte", ++ "Indian/Reunion", ++ "Pacific/Apia", ++ "Pacific/Auckland", ++ "Pacific/Chatham", ++ "Pacific/Easter", ++ "Pacific/Efate", ++ "Pacific/Enderbury", ++ "Pacific/Fakaofo", ++ "Pacific/Fiji", ++ "Pacific/Funafuti", ++ "Pacific/Galapagos", ++ "Pacific/Gambier", ++ "Pacific/Guadalcanal", ++ "Pacific/Guam", ++ "Pacific/Honolulu", ++ "Pacific/Johnston", ++ "Pacific/Kiritimati", ++ "Pacific/Kosrae", ++ "Pacific/Kwajalein", ++ "Pacific/Majuro", ++ "Pacific/Marquesas", ++ "Pacific/Midway", ++ "Pacific/Nauru", ++ "Pacific/Niue", ++ "Pacific/Norfolk", ++ "Pacific/Noumea", ++ "Pacific/Pago_Pago", ++ "Pacific/Palau", ++ "Pacific/Pitcairn", ++ "Pacific/Ponape", ++ "Pacific/Port_Moresby", ++ "Pacific/Rarotonga", ++ "Pacific/Saipan", ++ "Pacific/Tahiti", ++ "Pacific/Tarawa", ++ "Pacific/Tongatapu", ++ "Pacific/Truk", ++ "Pacific/Wake", ++ "Pacific/Wallis", ++ 0 ++}; ++ ++const int N_TIMEZONES = sizeof(IUnit::tblTimezone)/sizeof(const char*); ++ ++const QRegExp IUnit::reCoord1("^\\s*([N|S]){1}\\W*([0-9]+)\\W*([0-9]+\\.[0-9]+)\\s+([E|W|O]){1}\\W*([0-9]+)\\W*([0-9]+\\.[0-9]+)\\s*$"); ++ ++const QRegExp IUnit::reCoord2("^\\s*([N|S]){1}\\s*([0-9]+\\.[0-9]+)\\W*\\s+([E|W|O]){1}\\s*([0-9]+\\.[0-9]+)\\W*\\s*$"); ++ ++const QRegExp IUnit::reCoord3("^\\s*([-0-9]+\\.[0-9]+)\\s+([-0-9]+\\.[0-9]+)\\s*$"); ++ ++const QRegExp IUnit::reCoord4("^\\s*([N|S]){1}\\s*([0-9]+)\\W+([0-9]+)\\W+([0-9]+\\.[0-9]+)\\W*([E|W|O]){1}\\W*([0-9]+)\\W+([0-9]+)\\W+([0-9]+\\.[0-9]+)\\W*\\s*$"); ++ ++const QRegExp IUnit::reCoord5("^\\s*([-0-9]+\\.[0-9]+)([N|S])\\s+([-0-9]+\\.[0-9]+)([W|E])\\s*$"); ++ ++IUnit::IUnit(const type_e &type, const QString& baseunit, const qreal basefactor, const QString& speedunit, const qreal speedfactor, QObject * parent) ++ : QObject(parent) ++ , type(type) ++ , baseunit(baseunit) ++ , basefactor(basefactor) ++ , speedunit(speedunit) ++ , speedfactor(speedfactor) ++{ ++ //there can be only one... ++ if(nullptr != m_self) ++ { ++ delete m_self; ++ } ++ m_self = this; ++} ++ ++ ++void IUnit::setUnitType(type_e t, QObject * parent) ++{ ++ switch(t) ++ { ++ case eTypeMetric: ++ new CUnitMetric(parent); ++ break; ++ ++ case eTypeImperial: ++ new CUnitImperial(parent); ++ break; ++ ++ case eTypeNautic: ++ new CUnitNautic(parent); ++ break; ++ } ++ ++ QSettings cfg; ++ cfg.setValue("Units/type",t); ++} ++ ++void IUnit::meter2speed(qreal meter, QString& val, QString& unit) const ++{ ++ val.sprintf("%2.2f",meter * speedfactor); ++ unit = speedunit; ++} ++ ++void IUnit::seconds2time(quint32 ttime, QString& val, QString& unit) const ++{ ++ QTime time(0,0,0); ++ quint32 days = ttime / 86400; ++ ++ time = time.addSecs(ttime); ++ ++ if(days) ++ { ++ val = QString("%1:").arg(days) + time.toString("HH:mm:ss"); ++ unit = "d"; ++ } ++ else ++ { ++ val = time.toString("HH:mm:ss"); ++ unit = "h"; ++ } ++} ++ ++bool IUnit::parseTimestamp(const QString &time, QDateTime &datetime) ++{ ++ int tzoffset; ++ datetime = parseTimestamp(time, tzoffset); ++ ++ return datetime.isValid(); ++} ++ ++ ++QDateTime IUnit::parseTimestamp(const QString &timetext, int& tzoffset) ++{ ++ const QRegExp tzRE("[-+]\\d\\d:\\d\\d$"); ++ int i; ++ ++ tzoffset = 0; ++ ++ QString format = "yyyy-MM-dd'T'hh:mm:ss"; ++ ++ i = timetext.indexOf("."); ++ if (i != NOIDX) ++ { ++ if(timetext[i+1] == '0') ++ { ++ format += ".zzz"; ++ } ++ else ++ { ++ format += ".z"; ++ } ++ } ++ ++ // trailing "Z" explicitly declares the timestamp to be UTC ++ if (timetext.indexOf("Z") != NOIDX) ++ { ++ format += "'Z'"; ++ } ++ else if ((i = tzRE.indexIn(timetext)) != NOIDX) ++ { ++ // trailing timezone offset [-+]HH:MM present ++ // This does not match the original intentions of the GPX ++ // file format but appears to be found occasionally in ++ // the wild. Try our best parsing it. ++ ++ // add the literal string to the format so fromString() ++ // will succeed ++ format += "'"; ++ format += timetext.right(6); ++ format += "'"; ++ ++ // calculate the offset ++ int offsetHours(timetext.mid(i + 1, 2).toUInt()); ++ int offsetMinutes(timetext.mid(i + 4, 2).toUInt()); ++ if (timetext[i] == '-') ++ { ++ tzoffset = -(60 * offsetHours + offsetMinutes); ++ } ++ else ++ { ++ tzoffset = 60 * offsetHours + offsetMinutes; ++ } ++ tzoffset *= 60; // seconds ++ } ++ ++ QDateTime datetime = QDateTime::fromString(timetext, format); ++ datetime.setOffsetFromUtc(tzoffset); ++ ++ return datetime; ++} ++ ++QString IUnit::datetime2string(const QDateTime& time, bool shortDate, const QPointF& pos) ++{ ++ QTimeZone tz; ++ ++ tz_mode_e tmpMode = (pos != NOPOINTF) ? timeZoneMode : eTZLocal; ++ ++ switch(tmpMode) ++ { ++ case eTZUtc: ++ tz = QTimeZone("UTC"); ++ break; ++ ++ case eTZLocal: ++ tz = QTimeZone(QTimeZone::systemTimeZoneId()); ++ break; ++ ++ case eTZAuto: ++ tz = QTimeZone(pos2timezone(pos)); ++ break; ++ ++ case eTZSelected: ++ tz = QTimeZone(timeZone); ++ break; ++ } ++ ++ QDateTime tmp = time.toTimeZone(tz); ++ return tmp.toString((shortDate|useShortFormat) ? Qt::ISODate : Qt::SystemLocaleLongDate); ++} ++ ++QByteArray IUnit::pos2timezone(const QPointF& pos) ++{ ++ static QImage imgTimezone = QPixmap(":/pics/timezones.png").toImage(); ++ ++ int x = qRound(2048.0 / 360.0 * (180.0 + pos.x() * RAD_TO_DEG)); ++ int y = qRound(1024.0 / 180.0 * (90.0 - pos.y() * RAD_TO_DEG)); ++ ++ QRgb rgb = imgTimezone.pixel(x,y); ++ ++ if(qRed(rgb) == 0 && qGreen(rgb) == 0) ++ { ++ return "UTC"; ++ } ++ ++ int tz = ((qRed(rgb) & 248) << 1) + ((qGreen(rgb) >> 4) & 15); ++ if(tz >= N_TIMEZONES) ++ { ++ return 0; ++ } ++ ++ return tblTimezone[tz]; ++} ++ ++bool IUnit::degToStr(const qreal& x, const qreal& y, QString& str) ++{ ++ if(x < -180 || 180 < x) ++ { ++ return false; ++ } ++ ++ if(y < -90 || 90 < y) ++ { ++ return false; ++ } ++ ++ switch(coordFormat) ++ { ++ case eCoordFormat1: ++ { ++ qint32 degN,degE; ++ qreal minN,minE; ++ ++ bool signLat = GPS_Math_Deg_To_DegMin(y, °N, &minN); ++ bool signLon = GPS_Math_Deg_To_DegMin(x, °E, &minE); ++ ++ const QString &lat = signLat ? "S" : "N"; ++ const QString &lng = signLon ? "W" : "E"; ++ str.sprintf("%s%02d° %06.3f %s%03d° %06.3f",lat.toUtf8().data(),qAbs(degN),minN,lng.toUtf8().data(),qAbs(degE),minE); ++ break; ++ } ++ ++ case eCoordFormat2: ++ { ++ const QString &lat = (y < 0) ? "S" : "N"; ++ const QString &lng = (x < 0) ? "W" : "E"; ++ str.sprintf("%s%02.6f° %s%03.6f°",lat.toUtf8().data(),qAbs(y),lng.toUtf8().data(),qAbs(x)); ++ break; ++ } ++ ++ case eCoordFormat3: ++ { ++ qint32 degN,degE; ++ qreal minN,minE; ++ ++ bool signLat = GPS_Math_Deg_To_DegMin(y, °N, &minN); ++ bool signLon = GPS_Math_Deg_To_DegMin(x, °E, &minE); ++ ++ qreal secN = (minN - qFloor(minN)) * 60; ++ qreal secE = (minE - qFloor(minE)) * 60; ++ ++ const QString &lat = signLat ? "S" : "N"; ++ const QString &lng = signLon ? "W" : "E"; ++ str.sprintf("%s%02d° %02d' %02.2f'' %s%03d° %02d' %02.2f''",lat.toUtf8().data(),qAbs(degN),qFloor(minN),secN,lng.toUtf8().data(),qAbs(degE),qFloor(minE),secE); ++ break; ++ } ++ } ++ ++ return true; ++} ++ ++bool IUnit::strToDeg(const QString& str, qreal& lon, qreal& lat) ++{ ++ if(reCoord2.exactMatch(str)) ++ { ++ bool signLat = reCoord2.cap(1) == "S"; ++ qreal absLat = reCoord2.cap(2).toDouble(); ++ lat = signLat ? -absLat : absLat; ++ ++ bool signLon = reCoord2.cap(3) == "W"; ++ qreal absLon = reCoord2.cap(4).toDouble(); ++ lon = signLon ? -absLon : absLon; ++ } ++ else if(reCoord1.exactMatch(str)) ++ { ++ bool signLat = reCoord1.cap(1) == "S"; ++ int degLat = reCoord1.cap(2).toInt(); ++ qreal minLat = reCoord1.cap(3).toDouble(); ++ ++ GPS_Math_DegMin_To_Deg(signLat, degLat, minLat, lat); ++ ++ bool signLon = reCoord1.cap(4) == "W"; ++ int degLon = reCoord1.cap(5).toInt(); ++ qreal minLon = reCoord1.cap(6).toDouble(); ++ ++ GPS_Math_DegMin_To_Deg(signLon, degLon, minLon, lon); ++ } ++ else if(reCoord3.exactMatch(str)) ++ { ++ lat = reCoord3.cap(1).toDouble(); ++ lon = reCoord3.cap(2).toDouble(); ++ } ++ else if(reCoord4.exactMatch(str)) ++ { ++ bool signLat = reCoord4.cap(1) == "S"; ++ int degLat = reCoord4.cap(2).toInt(); ++ int minLat = reCoord4.cap(3).toInt(); ++ qreal secLat = reCoord4.cap(4).toFloat(); ++ ++ GPS_Math_DegMinSec_To_Deg(signLat, degLat, minLat, secLat, lat); ++ ++ bool signLon = reCoord4.cap(5) == "W"; ++ int degLon = reCoord4.cap(6).toInt(); ++ int minLon = reCoord4.cap(7).toInt(); ++ qreal secLon = reCoord4.cap(8).toFloat(); ++ ++ GPS_Math_DegMinSec_To_Deg(signLon, degLon, minLon, secLon, lon); ++ } ++ else if(reCoord5.exactMatch(str)) ++ { ++ bool signLon = reCoord4.cap(4) == "W"; ++ bool signLat = reCoord4.cap(2) == "S"; ++ lat = reCoord5.cap(1).toDouble(); ++ lon = reCoord5.cap(3).toDouble(); ++ ++ if(signLon) ++ { ++ lon = -lon; ++ } ++ if(signLat) ++ { ++ lat = -lat; ++ } ++ } ++ else ++ { ++ QMessageBox::warning(&CMainWindow::self(),tr("Error"),tr("Bad position format. Must be: \"[N|S] ddd mm.sss [W|E] ddd mm.sss\" or \"[N|S] ddd.ddd [W|E] ddd.ddd\""),QMessageBox::Ok,QMessageBox::NoButton); ++ return false; ++ } ++ ++ if(fabs(lon) > 180.0 || fabs(lat) > 90.0) ++ { ++ QMessageBox::warning(&CMainWindow::self(),tr("Error"),tr("Position values out of bounds. "),QMessageBox::Ok,QMessageBox::NoButton); ++ return false; ++ } ++ ++ return true; ++} ++ ++bool IUnit::isValidCoordString(const QString& str) ++{ ++ if(reCoord1.exactMatch(str)) ++ { ++ return true; ++ } ++ else if(reCoord2.exactMatch(str)) ++ { ++ return true; ++ } ++ else if(reCoord3.exactMatch(str)) ++ { ++ return true; ++ } ++ else if(reCoord4.exactMatch(str)) ++ { ++ return true; ++ } ++ else if(reCoord5.exactMatch(str)) ++ { ++ return true; ++ } ++ return false; ++} +diff --git a/src/qmaptool/units/IUnit.h b/src/qmaptool/units/IUnit.h +new file mode 100644 +index 00000000..f88077ac +--- /dev/null ++++ b/src/qmaptool/units/IUnit.h +@@ -0,0 +1,153 @@ ++/********************************************************************************************** ++ Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA ++ ++**********************************************************************************************/ ++#ifndef IUNIT_H ++#define IUNIT_H ++#include ++#include ++ ++ ++#define NOFLOAT 1000000000000.0 ++#define NOINT 0x7FFFFFFF ++#define NOTIME 0xFFFFFFFF ++#define NOIDX (-1) ++ ++extern const QPointF NOPOINTF; ++extern const QPoint NOPOINT; ++ ++class IUnit : public QObject ++{ ++ Q_OBJECT ++public: ++ virtual ~IUnit() = default; ++ ++ static const IUnit& self() ++ { ++ return *m_self; ++ } ++ ++ /// convert meter of elevation into a value and unit string ++ virtual void meter2elevation(qreal meter, QString& val, QString& unit) const = 0; ++ /// convert meter of distance into a value and unit string ++ virtual void meter2distance(qreal meter, QString& val, QString& unit) const = 0; ++ /// convert meter per second to a speed value string and unit label ++ virtual void meter2speed(qreal meter, QString& val, QString& unit) const; ++ /// convert square meter to string and unit label ++ virtual void meter2area(qreal meter, QString& val, QString& unit) const = 0; ++ /// convert seconds to a timespan of days, hours, minutes and seconds ++ virtual void seconds2time(quint32 ttime, QString& val, QString& unit) const; ++ /// convert an elevation string to a float ++ virtual qreal elevation2meter(const QString& val) const = 0; ++ /// convert a range in meter into a scale and a matching unit ++ virtual void meter2unit(qreal meter, qreal& scale, QString& unit) const = 0; ++ ++ ++ enum type_e {eTypeMetric, eTypeImperial, eTypeNautic}; ++ /// instantiate the correct unit object ++ static void setUnitType(type_e t, QObject * parent); ++ ++ /// parse a string for a timestamp ++ static bool parseTimestamp(const QString &time, QDateTime &datetime); ++ ++ /** ++ @brief Convert date time object to string using the current timezone configuration ++ ++ ++ @param time the date/time object ++ @param shortDate set true to get a short ISO time string ++ @param pos optional a position attached to the date/time object [rad] ++ @return A time string. ++ */ ++ static QString datetime2string(const QDateTime& time, bool shortDate, const QPointF& pos = NOPOINTF); ++ ++ /// find the timezone setup by position ++ static QByteArray pos2timezone(const QPointF& pos); ++ ++ const type_e type; ++ const QString baseunit; ++ const qreal basefactor; ++ const QString speedunit; ++ const qreal speedfactor; ++ static const char *tblTimezone[]; ++ ++ enum tz_mode_e ++ { ++ eTZUtc ++ ,eTZLocal ++ ,eTZAuto ++ ,eTZSelected ++ }; ++ ++ static void getTimeZoneSetup(tz_mode_e& mode, QByteArray& zone, bool& format) ++ { ++ mode = timeZoneMode; ++ zone = timeZone; ++ format = useShortFormat; ++ } ++ ++ static void setTimeZoneSetup(tz_mode_e mode, const QByteArray& zone, bool format) ++ { ++ timeZoneMode = mode; ++ timeZone = zone; ++ useShortFormat = format; ++ } ++ ++ enum coord_format_e ++ { ++ eCoordFormat1 ++ ,eCoordFormat2 ++ ,eCoordFormat3 ++ }; ++ ++ static enum coord_format_e getCoordFormat() ++ { ++ return coordFormat; ++ } ++ ++ static void setCoordFormat(const coord_format_e format) ++ { ++ coordFormat = format; ++ } ++ ++ static bool degToStr(const qreal& x, const qreal& y, QString& str); ++ ++ static bool strToDeg(const QString& str, qreal& lon, qreal& lat); ++ ++ static bool isValidCoordString(const QString& str); ++ ++protected: ++ IUnit(const type_e& type, const QString& baseunit, const qreal basefactor, const QString& speedunit, const qreal speedfactor, QObject *parent); ++ ++ static QDateTime parseTimestamp(const QString &timetext, int& tzoffset); ++ ++ static tz_mode_e timeZoneMode; ++ static QByteArray timeZone; ++ static bool useShortFormat; ++ ++ static coord_format_e coordFormat; ++ ++private: ++ static const IUnit * m_self; ++ ++ static const QRegExp reCoord1; ++ static const QRegExp reCoord2; ++ static const QRegExp reCoord3; ++ static const QRegExp reCoord4; ++ static const QRegExp reCoord5; ++}; ++#endif //IUNIT_H +diff --git a/src/qmaptool/units/IUnitsSetup.ui b/src/qmaptool/units/IUnitsSetup.ui +new file mode 100644 +index 00000000..4ccb69fd +--- /dev/null ++++ b/src/qmaptool/units/IUnitsSetup.ui +@@ -0,0 +1,125 @@ ++ ++ ++ IUnitsSetup ++ ++ ++ ++ 0 ++ 0 ++ 432 ++ 147 ++ ++ ++ ++ Setup units... ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Nautical ++ ++ ++ ++ ++ ++ ++ Imperial ++ ++ ++ ++ ++ ++ ++ Metric ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ <b>Note:</b> For some GUI elements changing the units will not take effect until you restart QMapTool. ++ ++ ++ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ ++ ++ Qt::Vertical ++ ++ ++ ++ 20 ++ 7 ++ ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ QDialogButtonBox::Cancel|QDialogButtonBox::Ok ++ ++ ++ ++ ++ ++ ++ ++ ++ buttonBox ++ accepted() ++ IUnitsSetup ++ accept() ++ ++ ++ 248 ++ 254 ++ ++ ++ 157 ++ 274 ++ ++ ++ ++ ++ buttonBox ++ rejected() ++ IUnitsSetup ++ reject() ++ ++ ++ 316 ++ 260 ++ ++ ++ 286 ++ 274 ++ ++ ++ ++ ++ +diff --git a/src/qmaptool/version.h b/src/qmaptool/version.h +new file mode 100644 +index 00000000..5e1ba038 +--- /dev/null ++++ b/src/qmaptool/version.h +@@ -0,0 +1,33 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef VERSION_H ++#define VERSION_H ++ ++#ifndef _MKSTR_1 ++#define _MKSTR_1(x) #x ++#define _MKSTR(x) _MKSTR_1(x) ++#endif ++ ++#define VER_STR _MKSTR(VER_MAJOR) "." _MKSTR (VER_MINOR) "." _MKSTR (VER_STEP) ++#define VER_SUFFIX _MKSTR(VER_TWEAK) ++ ++#define WHAT_STR "QMapTool, Version " VER_STR ++ ++#endif //VERSION_H ++ diff --git a/gis/qmapshack/line_3px_horizontal.png b/gis/qmapshack/line_3px_horizontal.png new file mode 100644 index 0000000000000..02c89c8dc461b Binary files /dev/null and b/gis/qmapshack/line_3px_horizontal.png differ diff --git a/gis/qmapshack/line_3px_vertical.png b/gis/qmapshack/line_3px_vertical.png new file mode 100644 index 0000000000000..f0f447c29133f Binary files /dev/null and b/gis/qmapshack/line_3px_vertical.png differ diff --git a/gis/qmapshack/qmapshack.SlackBuild b/gis/qmapshack/qmapshack.SlackBuild index af723abc20b7c..e8e62e063298e 100644 --- a/gis/qmapshack/qmapshack.SlackBuild +++ b/gis/qmapshack/qmapshack.SlackBuild @@ -10,7 +10,7 @@ # http://sam.zoy.org/wtfpl/COPYING for more details. PRGNAM=qmapshack -VERSION=${VERSION:-1.13.1} +VERSION=${VERSION:-1.13.2} BUILD=${BUILD:-1} TAG=${TAG:-_SBo} @@ -48,7 +48,18 @@ mkdir -p $TMP $PKG $OUTPUT cd $TMP rm -rf $PRGNAM-$VERSION tar xvf $CWD/$PRGNAM-$VERSION.tar.gz -cd $PRGNAM-$VERSION +cd ${PRGNAM}-V_${VERSION} + +# Patches provided in the source tree +patch -p1 < FindPROJ4.patch +patch -p1 < FindQuaZip5.patch +# Further patches and graphics required to build +patch -p1 < ${CWD}/addqmaptool.patch +patch -p1 < ${CWD}/qmt_map2jnx.patch +patch -p1 < ${CWD}/rgb2pct.patch +mkdir -p src/qmaptool/pic +cp ${CWD}/splash.png ${CWD}/line_3px_horizontal.png ${CWD}/line_3px_vertical.png src/qmaptool/pic + chown -R root:root . find -L . \ @@ -57,10 +68,6 @@ find -L . \ \( -perm 666 -o -perm 664 -o -perm 640 -o -perm 600 -o -perm 444 \ -o -perm 440 -o -perm 400 \) -exec chmod 644 {} \; -# Qmapshack expects proj to provide package information files created by cmake, the proj version on slackbuilds.org, however, is -# built using autotools, thus the config script fails. Again, thx to pAcAs for the hint. -cat $CWD/FindPROJ4.cmake > cmake/Modules/FindPROJ4.cmake - mkdir -p build cd build cmake \ diff --git a/gis/qmapshack/qmapshack.info b/gis/qmapshack/qmapshack.info index 7dd12a7a81980..ce1f5e3073288 100644 --- a/gis/qmapshack/qmapshack.info +++ b/gis/qmapshack/qmapshack.info @@ -1,10 +1,10 @@ PRGNAM="qmapshack" -VERSION="1.13.1" +VERSION="1.13.2" HOMEPAGE="https://bitbucket.org/maproom/qmapshack/wiki/Home" DOWNLOAD="UNSUPPORTED" MD5SUM="" -DOWNLOAD_x86_64="https://bitbucket.org/maproom/qmapshack/downloads/qmapshack-1.13.1.tar.gz" -MD5SUM_x86_64="5632d8318a93850b4cce731443aa64fe" +DOWNLOAD_x86_64="https://github.com/Maproom/qmapshack/archive/V_1.13.2/qmapshack-1.13.2.tar.gz" +MD5SUM_x86_64="1892583083d339bc393ce06919b7c4d9" REQUIRES="gdal qt5-webkit routino quazip-qt5" MAINTAINER="Daniel Stolarski" EMAIL="daniel.stolarski@gmail.com" diff --git a/gis/qmapshack/qmt_map2jnx.patch b/gis/qmapshack/qmt_map2jnx.patch new file mode 100644 index 0000000000000..50d5a2666626f --- /dev/null +++ b/gis/qmapshack/qmt_map2jnx.patch @@ -0,0 +1,1199 @@ +From 79a266943a40bee8fa5e71776c6a76c4d46bfbf8 Mon Sep 17 00:00:00 2001 +From: Oliver Eichler +Date: Thu, 12 Sep 2019 20:31:26 +0200 +Subject: [PATCH] [QMS-3] Add qmt_map2jnx from former sub-repo + +--- + src/qmt_map2jnx/CMakeLists.txt | 59 ++ + src/qmt_map2jnx/argv.cpp | 45 ++ + src/qmt_map2jnx/argv.h | 16 + + src/qmt_map2jnx/main.cpp | 1039 ++++++++++++++++++++++++++++++++ + 4 files changed, 1159 insertions(+) + create mode 100644 src/qmt_map2jnx/CMakeLists.txt + create mode 100644 src/qmt_map2jnx/argv.cpp + create mode 100644 src/qmt_map2jnx/argv.h + create mode 100644 src/qmt_map2jnx/main.cpp + +diff --git a/src/qmt_map2jnx/CMakeLists.txt b/src/qmt_map2jnx/CMakeLists.txt +new file mode 100644 +index 00000000..12b29d94 +--- /dev/null ++++ b/src/qmt_map2jnx/CMakeLists.txt +@@ -0,0 +1,59 @@ ++ ++ ++set(APPLICATION_NAME qmt_map2jnx) ++set(MAP2JNX_VERSION_MAJOR 1) ++set(MAP2JNX_VERSION_MINOR 0) ++set(MAP2JNX_VERSION_PATCH 0) ++ ++add_definitions( ++ -DVER_MAJOR=${MAP2JNX_VERSION_MAJOR} ++ -DVER_MINOR=${MAP2JNX_VERSION_MINOR} ++ -DVER_STEP=${MAP2JNX_VERSION_PATCH} ++ -DVER_TWEAK=${VERSION_SUFFIX} ++ -DAPPLICATION_NAME=${APPLICATION_NAME} ++) ++ ++ ++#if you don't want the full compiler output, remove the following line ++SET(CMAKE_VERBOSE_MAKEFILE ON) ++SET(SRCS main.cpp argv.cpp) ++SET(HDRS argv.h) ++ ++ ++include_directories( ++ ${CMAKE_BINARY_DIR} ++ ${CMAKE_CURRENT_BINARY_DIR} ++ ${GDAL_INCLUDE_DIRS} ++ ${PROJ4_INCLUDE_DIRS} ++ ${JPEG_INCLUDE_DIRS} ++) ++ ++if(APPLE) ++ INCLUDE_DIRECTORIES(/System/Library/Frameworks/Foundation.framework) ++ INCLUDE_DIRECTORIES(/System/Library/Frameworks/DiskArbitration.framework) ++endif(APPLE) ++ ++if(WIN32) ++ include_directories( ++ ${CMAKE_SOURCE_DIR}/Win32/ ++ ) ++endif(WIN32) ++ ++#list all source files here ++ADD_EXECUTABLE( ${APPLICATION_NAME} ${SRCS} ${HDRS}) ++ ++#add definitions, compiler switches, etc. ++IF(UNIX) ++ ADD_DEFINITIONS(-Wall) ++ENDIF(UNIX) ++ ++IF(WIN32) ++ ADD_DEFINITIONS(-D_CRT_SECURE_NO_DEPRECATE) ++ENDIF(WIN32) ++ ++TARGET_LINK_LIBRARIES(${APPLICATION_NAME} ${GDAL_LIBRARIES} ${PROJ4_LIBRARIES} ${JPEG_LIBRARIES}) ++ ++install( ++ TARGETS ${APPLICATION_NAME} DESTINATION ${BIN_INSTALL_DIR} ++) ++ +diff --git a/src/qmt_map2jnx/argv.cpp b/src/qmt_map2jnx/argv.cpp +new file mode 100644 +index 00000000..a7f7939c +--- /dev/null ++++ b/src/qmt_map2jnx/argv.cpp +@@ -0,0 +1,45 @@ ++/********************************************************************************************** ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++#include ++#include ++ ++#ifdef WIN32 ++#include ++#endif ++ ++char* get_argv(const int index, char** argv) ++{ ++ char* result = NULL; ++ int len; ++ ++#ifdef WIN32 ++ int numargs; ++ wchar_t** argw = CommandLineToArgvW(GetCommandLineW(), &numargs); ++ ++ // determine the buffer length first (including the trailing null) ++ len = WideCharToMultiByte(CP_UTF8, 0, argw[index], -1, NULL, 0, NULL, NULL); ++ result = (char*)calloc(len, 1); ++ WideCharToMultiByte(CP_UTF8, 0, argw[index], -1, result, len, NULL, NULL); ++ ++ GlobalFree(argw); ++#else ++ len = strlen(argv[index]) + 1; ++ result = (char*)calloc(len, 1); ++ strcpy(result, argv[index]); ++#endif ++ ++ return result; ++} +diff --git a/src/qmt_map2jnx/argv.h b/src/qmt_map2jnx/argv.h +new file mode 100644 +index 00000000..0967d0b7 +--- /dev/null ++++ b/src/qmt_map2jnx/argv.h +@@ -0,0 +1,16 @@ ++/********************************************************************************************** ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++char* get_argv(const int index, char** argv); +diff --git a/src/qmt_map2jnx/main.cpp b/src/qmt_map2jnx/main.cpp +new file mode 100644 +index 00000000..bef9cc43 +--- /dev/null ++++ b/src/qmt_map2jnx/main.cpp +@@ -0,0 +1,1039 @@ ++/********************************************************************************************** ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "config.h" ++ ++#ifdef _MSC_VER ++#define fseeko _fseeki64 ++#define ftello _ftelli64 ++#else ++#define _FILE_OFFSET_BITS 64 ++#endif // ++ ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++extern "C" ++{ ++#include ++} ++ ++#include "argv.h" ++ ++ ++#ifndef _MKSTR_1 ++#define _MKSTR_1(x) #x ++#define _MKSTR(x) _MKSTR_1(x) ++#endif ++ ++#define VER_STR _MKSTR(VER_MAJOR) "." _MKSTR(VER_MINOR) "." _MKSTR(VER_STEP) ++#define WHAT_STR "qmt_map2jnx, Version " VER_STR ++ ++#define JNX_MAX_TILES 50000 //6250 ++#define JNX_MAX_TILE_SIZE 1024 ++ ++#define JPG_BLOCK_SIZE (JNX_MAX_TILE_SIZE * JNX_MAX_TILE_SIZE) ++ ++#define HEADER_BLOCK_SIZE 1024 ++ ++#pragma pack(1) ++ ++struct jnx_hdr_t ++{ ++ jnx_hdr_t(): version(0x00000004), devid(0), expire(0), productId(0), crc(0), signature(0), signature_offset(0), zorder(25){} ++ uint32_t version; // byte 00000000..00000003 ++ uint32_t devid; // byte 00000004..00000007 ++ int32_t top; // byte 00000014..00000017 ++ int32_t right; // byte 00000010..00000013 ++ int32_t bottom; // byte 0000000C..0000000F ++ int32_t left; // byte 00000008..0000000B ++ uint32_t details; // byte 00000018..0000001B ++ uint32_t expire; // byte 0000001C..0000001F ++ uint32_t productId; // byte 00000020..00000023 ++ uint32_t crc; // byte 00000024..00000027 ++ uint32_t signature; // byte 00000028..0000002B ++ uint32_t signature_offset; // byte 0000002C..0000002F ++ uint32_t zorder; // byte 00000030..00000033 ++}; ++ ++ ++struct jnx_level_t ++{ ++ jnx_level_t(): nTiles(0), offset(0), scale(0), dummy(2){} ++ ++ uint32_t nTiles; ++ uint32_t offset; ++ uint32_t scale; ++ uint32_t dummy; ++}; ++ ++struct jnx_tile_t ++{ ++ jnx_tile_t() : top(0), right(0), bottom(0), left(0), width(0), height(0), size(0), offset(0){} ++ int32_t top; ++ int32_t right; ++ int32_t bottom; ++ int32_t left; ++ uint16_t width; ++ uint16_t height; ++ uint32_t size; ++ uint32_t offset; ++}; ++ ++ ++#ifdef WIN32 ++#pragma pack() ++#else ++#pragma pack(0) ++#endif ++ ++struct file_t ++{ ++ file_t(): dataset(0), pj(0){memset(colortable,0, sizeof(colortable));} ++ ~file_t() ++ { ++ //if(dataset) delete dataset; ++ if(pj) pj_free(pj); ++ } ++ ++ bool operator<(const file_t& other) const ++ { ++ return (xscale > other.xscale); ++ } ++ ++ std::string filename; ++ std::string projection; ++ GDALDataset * dataset; ++ projPJ pj; ++ uint32_t width; ++ uint32_t height; ++ double xscale; ++ double yscale; ++ double scale; ++ double xref1; ++ double yref1; ++ double xref2; ++ double yref2; ++ ++ double lon1; ++ double lat1; ++ double lon2; ++ double lat2; ++ ++ uint32_t colortable[256]; ++ ++}; ++ ++struct level_t : public jnx_level_t ++{ ++ std::list files; ++ uint32_t tileSize; ++}; ++ ++struct scale_t ++{ ++ double scale; ++ uint32_t jnxScale; ++}; ++ ++/// number of used levels ++static int32_t nLevels; ++/// up to five levels. nLevels gives the actual count ++static level_t levels[5]; ++/// information about all files ++static std::list files; ++/// the target lon/lat WGS84 projection ++static projPJ wgs84; ++/// the JNX file header to be copied to the outfile ++static jnx_hdr_t jnx_hdr; ++/// the tile information table for all 5 levels ++static jnx_tile_t tileTable[JNX_MAX_TILES * 5]; ++/// tile buffer for 8 bit palette tiles, private to readTile ++static uint8_t tileBuf8Bit[JNX_MAX_TILE_SIZE * JNX_MAX_TILE_SIZE] = {0}; ++/// tile buffer for 24 bit raw RGB tiles, private to writeTile ++static uint8_t tileBuf24Bit[JNX_MAX_TILE_SIZE * JNX_MAX_TILE_SIZE * 3] = {0}; ++/// tile buffer for 32 bit raw RGBA tiles ++static uint32_t tileBuf32Bit[JNX_MAX_TILE_SIZE * JNX_MAX_TILE_SIZE] = {0}; ++/// internal jpeg buffer used by write tile. ++static std::vector jpgbuf; ++ ++static void prinfFileinfo(const file_t& file) ++{ ++ printf("\n\n----------------------"); ++ printf("\n%s:", file.filename.c_str()); ++ printf("\nprojection: %s", file.projection.c_str()); ++ printf("\nwidth: %i pixel height: %i pixel", file.width, file.height); ++ ++ if(pj_is_latlong(file.pj)) ++ { ++ printf("\narea (top/left, bottom/right): %f %f, %f %f", file.lat1, file.lon1, file.lat2, file.lon2); ++ printf("\nxscale: %f °/px, yscale: %f °/px", file.xscale, file.yscale); ++ } ++ else ++ { ++ printf("\narea (top/left, bottom/right): %f %f, %f %f", file.lat1, file.lon1, file.lat2, file.lon2); ++ printf("\nxscale: %f m/px, yscale: %f m/px", file.xscale, file.yscale); ++ } ++ printf("\nreal scale: %f m/px", file.scale); ++} ++ ++bool readTile(uint32_t xoff, uint32_t yoff, uint32_t xsize, uint32_t ysize, file_t& file, uint32_t * output) ++{ ++ GDALDataset * dataset = file.dataset; ++ int32_t rasterBandCount = dataset->GetRasterCount(); ++ ++ memset(output,-1, sizeof(uint32_t) * xsize * ysize); ++ ++ if(rasterBandCount == 1) ++ { ++ GDALRasterBand * pBand; ++ pBand = dataset->GetRasterBand(1); ++ if(pBand->RasterIO(GF_Read,(int)xoff,(int)yoff, xsize, ysize, tileBuf8Bit,xsize,ysize,GDT_Byte,0,0) == CE_Failure) ++ { ++ return false; ++ } ++ ++ for(unsigned int i = 0; i < (xsize * ysize); i++) ++ { ++ output[i] = file.colortable[tileBuf8Bit[i]]; ++ } ++ } ++ else ++ { ++ for(int b = 1; b <= rasterBandCount; ++b) ++ { ++ GDALRasterBand * pBand; ++ pBand = dataset->GetRasterBand(b); ++ ++ uint32_t mask = ~(0x000000FF << (8*(b-1))); ++ ++ if(pBand->RasterIO(GF_Read,(int)xoff,(int)yoff, xsize, ysize, tileBuf8Bit,xsize,ysize,GDT_Byte,0,0) == CE_Failure) ++ { ++ return false; ++ } ++ ++ for(unsigned int i = 0; i < (xsize * ysize); i++) ++ { ++ uint32_t pixel = output[i]; ++ ++ pixel &= mask; ++ pixel |= tileBuf8Bit[i] << (8*(b-1)); ++ output[i] = pixel; ++ } ++ } ++ } ++ ++ return true; ++} ++ ++ ++ ++static void init_destination (j_compress_ptr cinfo) ++{ ++ jpgbuf.resize(JPG_BLOCK_SIZE); ++ cinfo->dest->next_output_byte = &jpgbuf[0]; ++ cinfo->dest->free_in_buffer = jpgbuf.size(); ++} ++ ++static boolean empty_output_buffer (j_compress_ptr cinfo) ++{ ++ size_t oldsize = jpgbuf.size(); ++ jpgbuf.resize(oldsize + JPG_BLOCK_SIZE); ++ cinfo->dest->next_output_byte = &jpgbuf[oldsize]; ++ cinfo->dest->free_in_buffer = jpgbuf.size() - oldsize; ++ return true; ++} ++ ++static void term_destination (j_compress_ptr cinfo) ++{ ++ jpgbuf.resize(jpgbuf.size() - cinfo->dest->free_in_buffer); ++} ++ ++ ++static uint32_t writeTile(uint32_t xsize, uint32_t ysize, uint32_t * raw_image, FILE * fid, int quality, int subsampling) ++{ ++ uint32_t size = 0; ++ struct jpeg_compress_struct cinfo; ++ struct jpeg_error_mgr jerr; ++ JSAMPROW row_pointer[1]; ++ ++ jpeg_destination_mgr destmgr = {0}; ++ destmgr.init_destination = init_destination; ++ destmgr.empty_output_buffer = empty_output_buffer; ++ destmgr.term_destination = term_destination; ++ ++ // convert from RGBA to RGB ++ for(uint32_t r = 0; r < ysize; r++) ++ { ++ for(uint32_t c = 0; c < xsize; c++) ++ { ++ uint32_t pixel = raw_image[r * xsize + c]; ++ tileBuf24Bit[r * xsize * 3 + c * 3] = pixel & 0x0FF; ++ tileBuf24Bit[r * xsize * 3 + c * 3 + 1] = (pixel >> 8) & 0x0FF; ++ tileBuf24Bit[r * xsize * 3 + c * 3 + 2] = (pixel >> 16) & 0x0FF; ++ } ++ } ++ ++ cinfo.err = jpeg_std_error( &jerr ); ++ jpeg_create_compress(&cinfo); ++ ++ cinfo.dest = &destmgr; ++ cinfo.image_width = xsize; ++ cinfo.image_height = ysize; ++ cinfo.input_components = 3; ++ cinfo.in_color_space = JCS_RGB; ++ ++ jpeg_set_defaults( &cinfo ); ++ ++ if (subsampling != -1) ++ { ++ switch (subsampling) ++ { ++ case 422: // 2x1, 1x1, 1x1 (4:2:2) : Medium ++ { ++ cinfo.comp_info[0].h_samp_factor = 2; ++ cinfo.comp_info[0].v_samp_factor = 1; ++ cinfo.comp_info[1].h_samp_factor = 1; ++ cinfo.comp_info[1].v_samp_factor = 1; ++ cinfo.comp_info[2].h_samp_factor = 1; ++ cinfo.comp_info[2].v_samp_factor = 1; ++ break; ++ } ++ case 411: // 2x2, 1x1, 1x1 (4:1:1) : High ++ { ++ cinfo.comp_info[0].h_samp_factor = 2; ++ cinfo.comp_info[0].v_samp_factor = 2; ++ cinfo.comp_info[1].h_samp_factor = 1; ++ cinfo.comp_info[1].v_samp_factor = 1; ++ cinfo.comp_info[2].h_samp_factor = 1; ++ cinfo.comp_info[2].v_samp_factor = 1; ++ break; ++ } ++ case 444: // 1x1 1x1 1x1 (4:4:4) : None ++ { ++ cinfo.comp_info[0].h_samp_factor = 1; ++ cinfo.comp_info[0].v_samp_factor = 1; ++ cinfo.comp_info[1].h_samp_factor = 1; ++ cinfo.comp_info[1].v_samp_factor = 1; ++ cinfo.comp_info[2].h_samp_factor = 1; ++ cinfo.comp_info[2].v_samp_factor = 1; ++ break; ++ } ++ } ++ } ++ ++ if (quality != -1) ++ { ++ jpeg_set_quality( &cinfo, quality, TRUE ); ++ } ++ ++ jpeg_start_compress( &cinfo, TRUE ); ++ ++ while( cinfo.next_scanline < cinfo.image_height ) ++ { ++ row_pointer[0] = (JSAMPLE*)&tileBuf24Bit[ cinfo.next_scanline * cinfo.image_width * cinfo.input_components]; ++ jpeg_write_scanlines( &cinfo, row_pointer, 1 ); ++ } ++ /* similar to read file, clean up after we're done compressing */ ++ jpeg_finish_compress( &cinfo ); ++ jpeg_destroy_compress( &cinfo ); ++ ++ // write data to output file ++ size = jpgbuf.size() - 2; ++ fwrite(&jpgbuf[2], size, 1, fid); ++ ++ return size; ++} ++ ++static double distance(const double u1, const double v1, const double u2, const double v2) ++{ ++ double dU = u2 - u1; // lambda ++ double dV = v2 - v1; // roh ++ ++ double d = 2*asin(sqrt(sin(dV/2) * sin(dV/2) + cos(v1) * cos(v2) * sin(dU/2) * sin(dU/2))); ++ ++ return 6371010 * d; ++} ++ ++static uint32_t scale2jnx(double scale) ++{ ++ /* ++ Ok, I've made some calculations, and got the following formula to ++ calculate the JNX scale (S) depending on the map's meters/pixel ++ ratio (R): ++ ++ S(R) = ++ qRound( ++ 76437 * ++ exp( ++ ln(2.000032708011) * ++ qRound( ++ ln(R * 130.2084 / 76437) / ++ ln(2.000032708011) ++ ) ++ ) ++ ) ++ ++ ++ where ++ qRound - is a function which returns the closest integer from ++ floating point value, [unfortunately its defined in C99 but not standard C++] ++ exp - exponent, ++ ln - natural logarithm. ++ ++ Magic number 130.2084 - is an average value for ++ (JNX scale) / (maps meters per pixel) ++ ratio among all zoom levels in metric system. ++ ++ Magic number 2.000032708011 is a ratio on which our standard scale ++ table is built. It is (76437 / 4777) ^ (1/4). ++ */ ++ ++ return (uint32_t)floor(0.5 + 76437 * exp(log(2.000032708011) * floor(0.5 + log(scale * 10 * 130.2084 / 76437) / log(2.000032708011) ) ) ); ++} ++ ++static char randChar() ++{ ++ char buf[2]; ++#if defined(HAVE_ARC4RANDOM) ++ int r = (int)((arc4random() * 16.0) / UINT_MAX); ++#else ++ int r = (int)((rand() * 16.0) / RAND_MAX); ++#endif ++ sprintf(buf,"%X", r & 0x0F); ++ return buf[0]; ++} ++ ++static void createGUID(char * guid) ++{ ++#if !defined(HAVE_ARC4RANDOM) ++ srand((unsigned int)time(0)); ++#endif ++ ++ guid[0] = randChar(); ++ guid[1] = randChar(); ++ guid[2] = randChar(); ++ guid[3] = randChar(); ++ guid[4] = randChar(); ++ guid[5] = randChar(); ++ guid[6] = randChar(); ++ guid[7] = randChar(); ++ guid[8] = '-'; ++ guid[9] = randChar(); ++ guid[10] = randChar(); ++ guid[11] = randChar(); ++ guid[12] = randChar(); ++ guid[13] = '-'; ++ guid[14] = randChar(); ++ guid[15] = randChar(); ++ guid[16] = randChar(); ++ guid[17] = randChar(); ++ guid[18] = '-'; ++ guid[19] = randChar(); ++ guid[20] = randChar(); ++ guid[21] = randChar(); ++ guid[22] = randChar(); ++ guid[23] = '-'; ++ guid[24] = randChar(); ++ guid[25] = randChar(); ++ guid[26] = randChar(); ++ guid[27] = randChar(); ++ guid[28] = randChar(); ++ guid[29] = randChar(); ++ guid[30] = randChar(); ++ guid[31] = randChar(); ++ guid[32] = randChar(); ++ guid[33] = randChar(); ++ guid[34] = randChar(); ++ guid[35] = randChar(); ++ guid[36] = 0; ++ ++} ++ ++/// this code is from the GDAL project ++static void printProgress(int current, int total) ++{ ++ double dfComplete = double(current)/double(total); ++ ++ static int nLastTick = -1; ++ int nThisTick = (int) (dfComplete * 40.0); ++ ++ nThisTick = MIN(40,MAX(0,nThisTick)); ++ ++ // Have we started a new progress run? ++ if( nThisTick < nLastTick && nLastTick >= 39 ) ++ { ++ nLastTick = -1; ++ } ++ ++ if( nThisTick <= nLastTick ) ++ { ++ return; ++ } ++ ++ while( nThisTick > nLastTick ) ++ { ++ nLastTick++; ++ if( nLastTick % 4 == 0 ) ++ { ++ fprintf( stdout, "%d", (nLastTick / 4) * 10 ); ++ } ++ else ++ { ++ fprintf( stdout, "." ); ++ } ++ } ++ ++ if( nThisTick == 40 ) ++ { ++ fprintf( stdout, " - done.\n" ); ++ } ++ else ++ { ++ fflush( stdout ); ++ } ++ ++} ++ ++ ++int main(int argc, char ** argv) ++{ ++ uint16_t tmp16; ++ const uint8_t dummy = 0; ++ uint32_t tileTableStart = 0; ++ uint32_t tileCnt = 0; ++ uint32_t tilesTotal = 0; ++ char projstr[1024]; ++ OGRSpatialReference oSRS; ++ int quality = -1; ++ int subsampling = -1; ++ ++ const char *copyright = "Unknown"; ++ const char *subscname = "BirdsEye"; ++ const char *mapname = "Unknown"; ++ ++ char *copyright_buf = NULL; ++ char *subscname_buf = NULL; ++ char *mapname_buf = NULL; ++ ++ std::vector forced_scale_values; ++ ++ printf("\n****** %s ******\n", WHAT_STR); ++ ++ if(argc < 2) ++ { ++ fprintf(stderr,"\nusage: qmt_map2jnx -q <1..100> -s <411|422|444> -p <0..> -c \"copyright notice\" -m \"BirdsEye\" -n \"Unknown\" -x file1_scale,file2_scale,...,fileN_scale ... \n"); ++ fprintf(stderr,"\n"); ++ fprintf(stderr," -q The JPEG quality from 1 to 100. Default is 75 \n"); ++ fprintf(stderr," -s The chroma subsampling. Default is 411 \n"); ++ fprintf(stderr," -p The product ID. Default is 0 \n"); ++ fprintf(stderr," -c The copyright notice. Default is \"Unknown\" \n"); ++ fprintf(stderr," -m The subscription product name. Default is \"BirdsEye\" \n"); ++ fprintf(stderr," -n The map name. Default is \"Unknown\" \n"); ++ fprintf(stderr," -z The z order (drawing order). Default is 25\n"); ++ fprintf(stderr," -x Override levels scale. Default: autodetect\n"); ++ fprintf(stderr,"\n"); ++ fprintf(stderr,"\nThe projection of the input files must have the same latitude along"); ++ fprintf(stderr,"\na pixel row. Mecator and Longitude/Latitude projections match this"); ++ fprintf(stderr,"\nthis property. Transversal Merkator or Lambert projections do not."); ++ fprintf(stderr,"\n"); ++ fprintf(stderr,"\nTo rectify a geotiff map, you can use the gdalwarp command, e.g."); ++ fprintf(stderr,"\ngdalwarp -t_srs \"EPSG:4326\" "); ++ fprintf(stderr,"\n"); ++ fprintf(stderr,"Scale levels must be pass in same order as level files pointed.\n"); ++ fprintf(stderr,"Empty and zero values equal to autodetect. We can point only needed\n"); ++ fprintf(stderr,"levels, like:\n"); ++ fprintf(stderr," -x 45356,,,75; -x ,,,,75\n"); ++ fprintf(stderr,"Calculated levels table can be found:\n"); ++ fprintf(stderr," English: http://whiter.brinkster.net/en/JNX.shtml\n"); ++ fprintf(stderr," Russian: http://whiter.brinkster.net/JNX.shtml\n"); ++ fprintf(stderr,"Most common values for different map scales:\n"); ++ fprintf(stderr," JNX scale Map scale\n"); ++ fprintf(stderr," ------------- ---------\n"); ++ fprintf(stderr," 78125-31250 1:1 000 000\n"); ++ fprintf(stderr," 20834-7813 1:500 000\n"); ++ fprintf(stderr," 7813-3125 1:200 000\n"); ++ fprintf(stderr," 3125-2084 1:100 000\n"); ++ fprintf(stderr," 2084-782 1:50 000\n"); ++ fprintf(stderr," 782-32 1:25 000\n"); ++ fprintf(stderr," 32-21 1:10 000\n"); ++ fprintf(stderr," 21-14 1:5000, 1:2000\n"); ++ fprintf(stderr,"\n"); ++ fprintf(stderr,"\n"); ++ exit(-1); ++ } ++ ++ GDALAllRegister(); ++ wgs84 = pj_init_plus("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"); ++ ++ // read geo information from input files ++ //files.resize(argc - 2); ++ int skip_next_arg = 0; ++ int files_count = 0; ++ ++ for(int i = 1; i < (argc - 1); i++) ++ { ++ if (skip_next_arg) ++ { ++ skip_next_arg = 0; ++ continue; ++ } ++ ++ if (argv[i][0] == '-') ++ { ++ if (towupper(argv[i][1]) == 'Q') ++ { ++ quality = atol(argv[i+1]); ++ skip_next_arg = 1; ++ continue; ++ } ++ else if (towupper(argv[i][1]) == 'S') ++ { ++ subsampling = atol(argv[i+1]); ++ skip_next_arg = 1; ++ continue; ++ } ++ else if (towupper(argv[i][1]) == 'P') ++ { ++ jnx_hdr.productId = atol(argv[i+1]); ++ skip_next_arg = 1; ++ continue; ++ } ++ else if (towupper(argv[i][1]) == 'C') ++ { ++ copyright = copyright_buf = get_argv(i + 1, argv); ++ skip_next_arg = 1; ++ continue; ++ } ++ else if (towupper(argv[i][1]) == 'M') ++ { ++ subscname = subscname_buf = get_argv(i + 1, argv); ++ skip_next_arg = 1; ++ continue; ++ } ++ else if (towupper(argv[i][1]) == 'N') ++ { ++ mapname = mapname_buf = get_argv(i + 1, argv); ++ skip_next_arg = 1; ++ continue; ++ } ++ else if (towupper(argv[i][1]) == 'Z') ++ { ++ jnx_hdr.zorder = atol(argv[i+1]); ++ skip_next_arg = 1; ++ continue; ++ } ++ else if (towupper(argv[i][1]) == 'X') ++ { ++ skip_next_arg = 1; ++ ++ std::string scales_buf(get_argv(i + 1, argv)); ++ size_t pos = 0; ++ size_t last_pos = 0; ++ ++ pos = scales_buf.find_first_of(','); ++ std::string val; ++ while (pos != std::string::npos) ++ { ++ val = scales_buf.substr(last_pos, pos - last_pos); ++ last_pos = pos + 1; ++ pos = scales_buf.find_first_of(',', pos + 1); ++ ++ //printf("val: %s : %d\n", val.c_str(), pos); ++ forced_scale_values.push_back(atol(val.c_str())); ++ } ++ val = scales_buf.substr(last_pos, pos); ++ //printf("val: %s : %d\n", val.c_str(), pos); ++ forced_scale_values.push_back(atol(val.c_str())); ++ ++ continue; ++ } ++ ++ } ++ ++ files_count++; ++ files.resize(files_count); ++ ++ double dist; ++ ++ GDALDataset * dataset = (GDALDataset*)GDALOpen(argv[i],GA_ReadOnly); ++ if(dataset == 0) ++ { ++ fprintf(stderr,"\nFailed to open %s\n", argv[i]); ++ exit(-1); ++ } ++ ++ projPJ pj; ++ char * ptr = projstr; ++ ++ if(dataset->GetProjectionRef()) ++ { ++ strncpy(projstr,dataset->GetProjectionRef(),sizeof(projstr)); ++ } ++ oSRS.importFromWkt(&ptr); ++ oSRS.exportToProj4(&ptr); ++ ++ pj = pj_init_plus(ptr); ++ if(pj == 0) ++ { ++ fprintf(stderr,"\nUnknown projection in file %s\n", argv[i]); ++ exit(-1); ++ } ++ ++ double adfGeoTransform[6]; ++ dataset->GetGeoTransform( adfGeoTransform ); ++ ++ std::list::iterator f = files.begin(); ++ std::advance(f, files_count - 1); ++ ++ file_t& file = *f; ++ file.filename = argv[i]; ++ file.projection = ptr; ++ file.dataset = dataset; ++ file.pj = pj; ++ file.width = dataset->GetRasterXSize(); ++ file.height = dataset->GetRasterYSize(); ++ file.xscale = adfGeoTransform[1]; ++ file.yscale = adfGeoTransform[5]; ++ file.xref1 = adfGeoTransform[0]; ++ file.yref1 = adfGeoTransform[3]; ++ file.xref2 = file.xref1 + file.width * file.xscale; ++ file.yref2 = file.yref1 + file.height * file.yscale; ++ ++ if(pj_is_latlong(file.pj)) ++ { ++ file.lon1 = file.xref1; ++ file.lat1 = file.yref1; ++ file.lon2 = file.xref2; ++ file.lat2 = file.yref2; ++ } ++ else ++ { ++ file.lon1 = file.xref1; ++ file.lat1 = file.yref1; ++ file.lon2 = file.xref2; ++ file.lat2 = file.yref2; ++ ++ pj_transform(pj,wgs84,1,0,&file.lon1,&file.lat1,0); ++ pj_transform(pj,wgs84,1,0,&file.lon2,&file.lat2,0); ++ ++ file.lon1 *= RAD_TO_DEG; ++ file.lat1 *= RAD_TO_DEG; ++ file.lon2 *= RAD_TO_DEG; ++ file.lat2 *= RAD_TO_DEG; ++ } ++ ++ dist = distance(file.lon1 * DEG_TO_RAD, file.lat1 * DEG_TO_RAD, file.lon2 * DEG_TO_RAD, file.lat1 * DEG_TO_RAD); ++ file.scale = dist/file.width; ++ ++ // fill color table if necessary ++ GDALRasterBand * pBand; ++ pBand = dataset->GetRasterBand(1); ++ ++ if(pBand->GetColorInterpretation() == GCI_PaletteIndex) ++ { ++ GDALColorTable * pct = pBand->GetColorTable(); ++ for(int c=0; c < pct->GetColorEntryCount(); ++c) ++ { ++ const GDALColorEntry& e = *pct->GetColorEntry(c); ++ file.colortable[c] = e.c1 | (e.c2 << 8) | (e.c3 << 16) | (e.c4 << 24); ++ } ++ } ++ else if(pBand->GetColorInterpretation() == GCI_GrayIndex ) ++ { ++ for(int c=0; c < 256; ++c) ++ { ++ file.colortable[c] = c | (c << 8) | (c << 16) | 0xFF000000; ++ } ++ } ++ ++ int success = 0; ++ int idx = (int)pBand->GetNoDataValue(&success); ++ ++ if(success) ++ { ++ file.colortable[idx] &= 0x00FFFFFF; ++ } ++ } ++ ++ // apply sorted files to levels and extract file header data ++ double right = -180.0; ++ double top = -90.0; ++ double left = 180.0; ++ double bottom = 90.0; ++ ++ double scale = 0.0; ++ files.sort(); ++ std::list::iterator f; ++ for(f = files.begin(); f != files.end(); f++) ++ { ++ file_t& file = *f; ++ prinfFileinfo(file); ++ ++ if(file.lon1 < left) left = file.lon1; ++ if(file.lat1 > top) top = file.lat1; ++ if(file.lat2 < bottom) bottom = file.lat2; ++ if(file.lon2 > right) right = file.lon2; ++ ++ if(scale != 0.0 && ((fabs(scale - file.xscale)) / scale) > 0.02) ++ { ++ nLevels++; ++ if(nLevels > 4) ++ { ++ fprintf(stderr,"\nToo many different detail levels.\n"); ++ exit(-1); ++ } ++ } ++ scale = file.xscale; ++ ++ levels[nLevels].files.push_back(&file); ++ } ++ nLevels++; ++ ++ FILE * fid = fopen(argv[argc-1],"wb"); ++ if(fid == 0) ++ { ++ fprintf(stderr,"\nFailed to create file %s\n", argv[argc-1]); ++ exit(-1); ++ } ++ ++ jnx_hdr.left = (int32_t)((left * 0x7FFFFFFF) / 180); ++ jnx_hdr.top = (int32_t)((top * 0x7FFFFFFF) / 180); ++ jnx_hdr.right = (int32_t)((right * 0x7FFFFFFF) / 180); ++ jnx_hdr.bottom = (int32_t)((bottom * 0x7FFFFFFF) / 180); ++ ++ jnx_hdr.details = nLevels; ++ ++ printf("\n\n======== map header ========"); ++ printf("\nmap area (top/left, bottom/right): %f %f, %f %f", left, top, right, bottom); ++ printf("\n %08X %08X, %08X %08X", jnx_hdr.left, jnx_hdr.top, jnx_hdr.right, jnx_hdr.bottom); ++ printf("\nnumber of detail levels: %i", jnx_hdr.details); ++ printf("\nz-order: %i\n", jnx_hdr.zorder); ++ ++ ++ for(int i=0; i::iterator f; ++ double scale = 0.0; ++ ++ while(size <= JNX_MAX_TILE_SIZE) ++ { ++ level.nTiles = 0; ++ level.tileSize = size; ++ for(f = level.files.begin(); f != level.files.end(); f++) ++ { ++ file_t& file = *(*f); ++ double xTiles = file.width / double(size); ++ double yTiles = file.height / double(size); ++ level.nTiles += int(ceil(xTiles)) * int(ceil(yTiles)); ++ ++ scale = file.scale; ++ } ++ ++ if(level.nTiles < JNX_MAX_TILES) ++ { ++ break; ++ } ++ size <<= 1; ++ } ++ ++ ++ level.offset = tilesTotal * sizeof(jnx_tile_t) + HEADER_BLOCK_SIZE; // still has to be offset by complete header ++ if (forced_scale_values.size() == 0 || (unsigned)i >= forced_scale_values.size() || forced_scale_values[i] == 0) ++ { ++ level.scale = scale2jnx(scale); ++ } ++ else ++ { ++ level.scale = forced_scale_values[i]; ++ } ++ tilesTotal += level.nTiles; ++ ++ fwrite(&level.nTiles, sizeof(level.nTiles), 1, fid); ++ fwrite(&level.offset, sizeof(level.offset), 1, fid); ++ fwrite(&level.scale, sizeof(level.scale), 1, fid); ++ fwrite(&level.dummy, sizeof(level.dummy), 1, fid); ++ fwrite(copyright, strlen(copyright) + 1, 1, fid); ++ ++ ++ printf("\n Level %i: % 5i tiles, offset %08X, scale: %i, %ix%i", i, level.nTiles, level.offset, level.scale, level.tileSize, level.tileSize); ++ ++ } ++ ++ // -------------------------------------------------------------- ++ // write map loader info block ++ uint32_t blockVersion = 0x00000009; ++ char GUID[40]; ++ createGUID(GUID); ++ ++ tmp16 = jnx_hdr.productId; ++ ++ fwrite(&blockVersion, sizeof(blockVersion), 1, fid); ++ fwrite(GUID, 37, 1, fid); ++ fwrite(subscname, strlen(subscname) + 1, 1, fid); ++ fwrite(&dummy, sizeof(dummy), 1, fid); ++ fwrite(&tmp16, sizeof(tmp16), 1, fid); ++ fwrite(mapname, strlen(mapname) + 1, 1, fid); ++ fwrite(&nLevels , sizeof(nLevels), 1, fid); ++ for(int i = 1; i <= nLevels; i++) ++ { ++ char str[40]; ++ sprintf(str,"Level %i", i); ++ fwrite(str, strlen(str) + 1, 1, fid); ++ fwrite(str, strlen(str) + 1, 1, fid); ++ fwrite(copyright, strlen(copyright) + 1, 1, fid); ++ fwrite(&i,sizeof(i), 1, fid); ++ } ++ ++ // -------------------------------------------------------------- ++ // write dummy tile table ++ tileTableStart = HEADER_BLOCK_SIZE; ++ fseeko(fid, tileTableStart, SEEK_SET); ++ fwrite(tileTable, sizeof(jnx_tile_t), tilesTotal, fid); ++ ++ // -------------------------------------------------------------- ++ // read tiles from input files and write jpeg coded tiles to output file ++ printf("\n\nStart conversion:\n"); ++ for(int l = 0; l < nLevels; l++) ++ { ++ level_t& level = levels[l]; ++ ++ std::list::iterator f; ++ for(f = level.files.begin(); f != level.files.end(); f++) ++ { ++ file_t& file = *(*f); ++ ++ uint32_t xoff = 0; ++ uint32_t yoff = 0; ++ ++ uint32_t xsize = level.tileSize; ++ uint32_t ysize = level.tileSize; ++ ++ while(yoff < file.height) ++ { ++ if(ysize > (file.height - yoff)) ++ { ++ ysize = file.height - yoff; ++ } ++ ++ xsize = level.tileSize; ++ xoff = 0; ++ ++ while(xoff < file.width) ++ { ++ if(xsize > (file.width - xoff)) ++ { ++ xsize = (file.width - xoff); ++ } ++ ++ // // ++ if(!readTile(xoff, yoff, xsize, ysize, file, tileBuf32Bit)) ++ { ++ fprintf(stderr,"\nError reading tiles from map file\n"); ++ exit(-1); ++ } ++ ++ jnx_tile_t& tile = tileTable[tileCnt++]; ++ if(pj_is_latlong(file.pj)) ++ { ++ ++ double u1 = file.lon1 + xoff * file.xscale; ++ double v1 = file.lat1 + yoff * file.yscale; ++ double u2 = file.lon1 + (xoff + xsize) * file.xscale; ++ double v2 = file.lat1 + (yoff + ysize) * file.yscale; ++ ++ ++ tile.left = (int32_t)(u1 * 0x7FFFFFFF / 180); ++ tile.top = (int32_t)(v1 * 0x7FFFFFFF / 180); ++ tile.right = (int32_t)(u2 * 0x7FFFFFFF / 180); ++ tile.bottom = (int32_t)(v2 * 0x7FFFFFFF / 180); ++ ++ } ++ else ++ { ++ double u1 = file.xref1 + xoff * file.xscale; ++ double v1 = file.yref1 + yoff * file.yscale; ++ double u2 = file.xref1 + (xoff + xsize) * file.xscale; ++ double v2 = file.yref1 + (yoff + ysize) * file.yscale; ++ ++ pj_transform(file.pj,wgs84,1,0,&u1,&v1,0); ++ pj_transform(file.pj,wgs84,1,0,&u2,&v2,0); ++ ++ tile.left = (int32_t)((u1 * RAD_TO_DEG) * 0x7FFFFFFF / 180); ++ tile.top = (int32_t)((v1 * RAD_TO_DEG) * 0x7FFFFFFF / 180); ++ tile.right = (int32_t)((u2 * RAD_TO_DEG) * 0x7FFFFFFF / 180); ++ tile.bottom = (int32_t)((v2 * RAD_TO_DEG) * 0x7FFFFFFF / 180); ++ } ++ ++ tile.width = xsize; ++ tile.height = ysize; ++ tile.offset = (uint32_t)(ftello(fid) & 0x0FFFFFFFF); ++ tile.size = writeTile(xsize, ysize, tileBuf32Bit, fid, quality, subsampling); ++ ++ printProgress(tileCnt, tilesTotal); ++ // // ++ xoff += xsize; ++ } ++ ++ yoff += ysize; ++ } ++ } ++ } ++ ++ // terminate output file ++ fwrite("BirdsEye", 8, 1, fid); ++ ++ // write final tile table ++ fseeko(fid, tileTableStart, SEEK_SET); ++ fwrite(tileTable, sizeof(jnx_tile_t), tilesTotal, fid); ++ // done ++ fclose(fid); ++ ++ // clean up ++ pj_free(wgs84); ++ GDALDestroyDriverManager(); ++ if (copyright_buf) ++ free(copyright_buf); ++ if (subscname_buf) ++ free(subscname_buf); ++ if (mapname_buf) ++ free(mapname_buf); ++ printf("\n\n"); ++ return 0; ++} diff --git a/gis/qmapshack/rgb2pct.patch b/gis/qmapshack/rgb2pct.patch new file mode 100644 index 0000000000000..92c5df87762fd --- /dev/null +++ b/gis/qmapshack/rgb2pct.patch @@ -0,0 +1,971 @@ +From 763cfc149566325cce9e4690cb7b5f986048f86a Mon Sep 17 00:00:00 2001 +From: Oliver Eichler +Date: Thu, 12 Sep 2019 20:32:06 +0200 +Subject: [PATCH] [QMS-3] Add qmt_rgb2pct from former sub-repo + +--- + src/qmt_rgb2pct/CApp.cpp | 280 +++++++++++++++++++++++ + src/qmt_rgb2pct/CApp.h | 55 +++++ + src/qmt_rgb2pct/CMakeLists.txt | 117 ++++++++++ + src/qmt_rgb2pct/README.md | 5 + + src/qmt_rgb2pct/locale/qmt_rgb2pct.ts | 126 ++++++++++ + src/qmt_rgb2pct/locale/qmt_rgb2pct_de.ts | 127 ++++++++++ + src/qmt_rgb2pct/main.cpp | 155 +++++++++++++ + src/qmt_rgb2pct/version.h | 33 +++ + 8 files changed, 898 insertions(+) + create mode 100644 src/qmt_rgb2pct/CApp.cpp + create mode 100644 src/qmt_rgb2pct/CApp.h + create mode 100644 src/qmt_rgb2pct/CMakeLists.txt + create mode 100644 src/qmt_rgb2pct/README.md + create mode 100644 src/qmt_rgb2pct/locale/qmt_rgb2pct.ts + create mode 100644 src/qmt_rgb2pct/locale/qmt_rgb2pct_de.ts + create mode 100644 src/qmt_rgb2pct/main.cpp + create mode 100644 src/qmt_rgb2pct/version.h + +diff --git a/src/qmt_rgb2pct/CApp.cpp b/src/qmt_rgb2pct/CApp.cpp +new file mode 100644 +index 00000000..993ed759 +--- /dev/null ++++ b/src/qmt_rgb2pct/CApp.cpp +@@ -0,0 +1,280 @@ ++/********************************************************************************************** ++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "CApp.h" ++ ++#include ++#include ++#include ++ ++const GDALColorEntry CApp::noColor = {255,255,255,0}; ++ ++void printStdoutQString(const QString& str) ++{ ++ QByteArray array = str.toUtf8(); ++ printf("%s", array.data()); ++ printf("\n"); ++} ++ ++void printStderrQString(const QString& str) ++{ ++ QByteArray array = str.toUtf8(); ++ fprintf(stderr, "%s", array.data()); ++ fprintf(stderr, "\n"); ++} ++ ++ ++ ++CApp::CApp(qint32 ncolors, const QString& pctFilename, const QString &sctFilename, const QString &srcFilename, const QString &tarFilename) ++ : ncolors(ncolors) ++ , pctFilename(pctFilename) ++ , sctFilename(sctFilename) ++ , srcFilename(srcFilename) ++ , tarFilename(tarFilename) ++{ ++ GDALAllRegister(); ++} ++ ++qint32 CApp::exec() ++{ ++ qint32 res = 0; ++ GDALColorTable * ct = nullptr; ++ GDALDataset * dsSrc = nullptr; ++ try ++ { ++ dsSrc = (GDALDataset*)GDALOpenShared(srcFilename.toUtf8(),GA_ReadOnly); ++ if(dsSrc == nullptr) ++ { ++ throw tr("Failed to open source file."); ++ } ++ ++ if(dsSrc->GetRasterCount() < 3 || dsSrc->GetRasterCount() > 4) ++ { ++ throw tr("Raster band count of source file must be either 3 or 4."); ++ } ++ ++ if(QFile(tarFilename).exists()) ++ { ++ QFile::remove(tarFilename); ++ } ++ ++ ct = createColorTable(ncolors, pctFilename, dsSrc); ++ saveColorTable(ct, sctFilename); ++ ditherMap(dsSrc, tarFilename, ct); ++ } ++ catch(const QString& msg) ++ { ++ printStderrQString(msg); ++ res = -1; ++ } ++ ++ ++ GDALClose(dsSrc); ++ delete ct; ++ return res; ++} ++ ++GDALColorTable * CApp::createColorTable(qint32 ncolors, const QString& pctFilename, GDALDataset * dataset) ++{ ++ GDALColorTable * ct = nullptr; ++ try ++ { ++ if(pctFilename.isEmpty()) ++ { ++ ct = (GDALColorTable*)GDALCreateColorTable(GPI_RGB); ++ ++ printStdoutQString(tr("Calculate optimal color table from source file")); ++ ++ int ok = GDALComputeMedianCutPCT(dataset->GetRasterBand(1), ++ dataset->GetRasterBand(2), ++ dataset->GetRasterBand(3), ++ nullptr, ++ ncolors, ++ ct, ++ GDALTermProgress, ++ 0 ++ ); ++ ++ if(ok != CE_None) ++ { ++ throw tr("Failed to create color table."); ++ } ++ } ++ else ++ { ++ GDALDataset * dsPct = (GDALDataset*)GDALOpenShared(pctFilename.toUtf8(),GA_ReadOnly); ++ if(dsPct == nullptr) ++ { ++ throw tr("Failed to open file with palette."); ++ } ++ ++ GDALRasterBand * band = (GDALRasterBand*)dsPct->GetRasterBand(1); ++ ++ if((dsPct->GetRasterCount() != 1) || (band->GetColorInterpretation() != GCI_PaletteIndex)) ++ { ++ GDALClose(dsPct); ++ throw tr("Palette file does not have a single band with a color table"); ++ } ++ ++ int ok = 0; ++ band->GetNoDataValue(&ok); ++ ++ if(ok || band->GetColorTable()->GetColorEntryCount() > 255) ++ { ++ GDALClose(dsPct); ++ throw tr("The color table must not contain a \"no data\" value and it's size must not exceed 255 colors."); ++ } ++ ++ ct = dsPct->GetRasterBand(1)->GetColorTable()->Clone(); ++ } ++ } ++ catch(const QString& msg) ++ { ++ delete ct; ++ throw msg; ++ } ++ return ct; ++} ++ ++void CApp::saveColorTable(GDALColorTable * ct, QString& sctFilename) ++{ ++ if(sctFilename.isEmpty()) ++ { ++ return; ++ } ++ ++ if(!sctFilename.endsWith(".vrt")) ++ { ++ sctFilename += ".vrt"; ++ } ++ ++ QByteArray buf = sctFilename.toUtf8(); ++ printStdoutQString(tr("Save color table to: %1").arg(buf.data())); ++ ++ GDALDriverManager * drvman = GetGDALDriverManager(); ++ GDALDriver * driver = drvman->GetDriverByName("VRT"); ++ GDALDataset * dataset = driver->Create(sctFilename.toUtf8(), 1, 1, 1, GDT_Byte, {}); ++ ++ dataset->GetRasterBand(1)->SetColorInterpretation(GCI_PaletteIndex); ++ dataset->GetRasterBand(1)->SetColorTable(ct); ++ ++ dataset->FlushCache(); ++ GDALClose(dataset); ++} ++ ++void CApp::ditherMap(GDALDataset * dsSrc, const QString& tarFilename, GDALColorTable *ct) ++{ ++ if(tarFilename.isEmpty()) ++ { ++ return; ++ } ++ ++ qint32 xsize = dsSrc->GetRasterBand(1)->GetXSize(); ++ qint32 ysize = dsSrc->GetRasterBand(1)->GetYSize(); ++ ++ GDALDriverManager * drvman = nullptr; ++ GDALDriver * driver = nullptr; ++ GDALDataset * dataset = nullptr; ++ ++ try ++ { ++ const char * cargs[] = {"TILED=YES","COMPRESS=LZW", 0}; ++ drvman = GetGDALDriverManager(); ++ driver = drvman->GetDriverByName("GTiff"); ++ dataset = driver->Create(tarFilename.toUtf8(), xsize, ysize, 1, GDT_Byte, (char**)cargs); ++ ++ if(dataset == nullptr) ++ { ++ throw tr("Failed to create target file."); ++ } ++ ++ dataset->GetRasterBand(1)->SetColorTable(ct); ++ dataset->GetRasterBand(1)->SetNoDataValue(ct->GetColorEntryCount()); ++ dataset->SetProjection(dsSrc->GetProjectionRef()); ++ ++ double adfGeoTransform[6] = {0}; ++ dsSrc->GetGeoTransform(adfGeoTransform); ++ dataset->SetGeoTransform(adfGeoTransform); ++ ++ printStdoutQString(tr("Dither source file to target file")); ++ int res = GDALDitherRGB2PCT(dsSrc->GetRasterBand(1), ++ dsSrc->GetRasterBand(2), ++ dsSrc->GetRasterBand(3), ++ dataset->GetRasterBand(1), ++ ct, ++ GDALTermProgress, ++ 0 ++ ); ++ if(res != CE_None) ++ { ++ throw tr("Failed to dither file."); ++ } ++ ++ if(dsSrc->GetRasterCount() == 3) ++ { ++ return; ++ } ++ ++ GDALRasterBand * alpha = dsSrc->GetRasterBand(4); ++ GDALRasterBand * band = dataset->GetRasterBand(1); ++ ++ QByteArray buffer1(xsize, 0); ++ QByteArray buffer2(xsize, 0); ++ ++ quint8 nodata = band->GetNoDataValue(); ++ printStdoutQString(tr("Apply alpha channel as no data value to target file")); ++ for(int y = 0; y < ysize; y++) ++ { ++ GDALTermProgress(double(xsize * y)/(xsize*ysize),0,0); ++ res = alpha->RasterIO(GF_Read, 0, y, xsize, 1, buffer1.data(), xsize, 1, GDT_Byte, 0, 0); ++ if(res != CE_None) ++ { ++ throw tr("Failed to read from alpha channel."); ++ } ++ ++ res = band->RasterIO(GF_Read, 0, y, xsize, 1, buffer2.data(), xsize, 1, GDT_Byte, 0, 0); ++ if(res != CE_None) ++ { ++ throw tr("Failed to read from target file."); ++ } ++ ++ for(int x = 0; x < xsize; x++) ++ { ++ if(buffer1[x] != char(0xFF)) ++ { ++ buffer2[x] = nodata; ++ } ++ } ++ ++ res = band->RasterIO(GF_Write, 0, y, xsize, 1, buffer2.data(), xsize, 1, GDT_Byte, 0, 0); ++ if(res != CE_None) ++ { ++ throw tr("Failed to write to target file."); ++ } ++ } ++ GDALTermProgress(1.0,0,0); ++ } ++ catch(const QString& msg) ++ { ++ GDALClose(dataset); ++ throw msg; ++ } ++ ++ dataset->FlushCache(); ++ GDALClose(dataset); ++} +diff --git a/src/qmt_rgb2pct/CApp.h b/src/qmt_rgb2pct/CApp.h +new file mode 100644 +index 00000000..e2e0f7ca +--- /dev/null ++++ b/src/qmt_rgb2pct/CApp.h +@@ -0,0 +1,55 @@ ++/********************************************************************************************** ++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef CAPP_H ++#define CAPP_H ++ ++#include ++#include ++ ++class GDALColorTable; ++class GDALDataset; ++ ++class CApp ++{ ++ Q_DECLARE_TR_FUNCTIONS(CApp) ++public: ++ CApp(qint32 ncolors, const QString& pctFilename, const QString& sctFilename, const QString& srcFilename, const QString& tarFilename); ++ virtual ~CApp() = default; ++ ++ qint32 exec(); ++ ++private: ++ static GDALColorTable * createColorTable(qint32 ncolors, const QString& pctFilename, GDALDataset *dataset); ++ static void saveColorTable(GDALColorTable *ct, QString &sctFilename); ++ static void ditherMap(GDALDataset * dsSrc, const QString& tarFilename, GDALColorTable *ct); ++ ++ qint32 ncolors = 0; ++ QString pctFilename; ++ QString sctFilename; ++ QString srcFilename; ++ QString tarFilename; ++ ++ static const GDALColorEntry noColor; ++}; ++ ++void printStdoutQString(const QString& str); ++void printStderrQString(const QString& str); ++ ++#endif //CAPP_H ++ +diff --git a/src/qmt_rgb2pct/CMakeLists.txt b/src/qmt_rgb2pct/CMakeLists.txt +new file mode 100644 +index 00000000..c763595e +--- /dev/null ++++ b/src/qmt_rgb2pct/CMakeLists.txt +@@ -0,0 +1,117 @@ ++# Prevent custom commands/targets outputs to be deleted by make clean ++# We need this to prevent .ts files from being deleted with make clean, when ++# UPDATE_TRANSLATIONS=ON ++# WARNING: Only works with Makefile generator. ++set_directory_properties(PROPERTIES CLEAN_NO_CUSTOM TRUE) ++# Find includes in corresponding build directories ++set(CMAKE_INCLUDE_CURRENT_DIR ON) ++# Instruct CMake to run moc automatically when needed. ++set(CMAKE_AUTOMOC ON) ++ ++############################################################################################### ++# Setup application name and version tags ++############################################################################################### ++ ++set(APPLICATION_NAME qmt_rgb2pct) ++set(RGB2PCT_VERSION_MAJOR 1) ++set(RGB2PCT_VERSION_MINOR 0) ++set(RGB2PCT_VERSION_PATCH 0) ++ ++add_definitions( ++ -DVER_MAJOR=${RGB2PCT_VERSION_MAJOR} ++ -DVER_MINOR=${RGB2PCT_VERSION_MINOR} ++ -DVER_STEP=${RGB2PCT_VERSION_PATCH} ++ -DVER_TWEAK=${VERSION_SUFFIX} ++ -DAPPLICATION_NAME=${APPLICATION_NAME} ++) ++ ++############################################################################################### ++# All source files needed to compile ++############################################################################################### ++set( SRCS ++ main.cpp ++ CApp.cpp ++) ++ ++set( HDRS ++ version.h ++ CApp.h ++) ++ ++set( UIS ++) ++ ++set( RCS ++) ++ ++############################################################################################### ++# Some Qt magic ++############################################################################################### ++ ++qt5_wrap_ui(UI_HDRS ${UIS}) ++qt5_add_resources(RC_SRCS ${RCS}) ++ ++############################################################################################### ++# Translation related stuff ++############################################################################################### ++translate_ts(${APPLICATION_NAME}_QM_FILES ++ UPDATE_TRANSLATIONS ${UPDATE_TRANSLATIONS} ++ UPDATE_OPTIONS "-I${CMAKE_CURRENT_SOURCE_DIR}" ${KEEP_OLD_TRANSLATIONS} ++ SOURCES ${SRCS} ${HDRS} ${UIS} ++ TEMPLATE ${APPLICATION_NAME} ++ TRANSLATION_DIR "locale" ++) ++ ++############################################################################################### ++# Build source file and include paths lists ++############################################################################################### ++set(MAININP ++ ${SRCS} ++ ${HDRS} ++ ${UI_HDRS} ++ ${RC_SRCS} ++ ${${APPLICATION_NAME}_QM_FILES} ++ ${${APPLICATION_NAME}_DESKTOP_FILES} ++) ++ ++include_directories( ++ SYSTEM # this prevents warnings from non-QMS headers ++ ${CMAKE_BINARY_DIR} ++ ${GDAL_INCLUDE_DIRS} ++ ${PROJ4_INCLUDE_DIRS} ++) ++ ++if(APPLE) ++ INCLUDE_DIRECTORIES(/System/Library/Frameworks/Foundation.framework) ++ INCLUDE_DIRECTORIES(/System/Library/Frameworks/DiskArbitration.framework) ++endif(APPLE) ++ ++ ++############################################################################################### ++# Build the executable and define necessary libraries. ++############################################################################################### ++add_executable(${APPLICATION_NAME} WIN32 ${MAININP}) ++ ++target_link_libraries(${APPLICATION_NAME} ++ Qt5::Core ++ ${GDAL_LIBRARIES} ++ ${PROJ4_LIBRARIES} ++) ++ ++if(APPLE) ++ target_link_libraries(${APPLICATION_NAME} ++ ${Foundation_LIBRARY} ++ ${DiskArbitration_LIBRARY} ++ ) ++endif(APPLE) ++ ++ ++############################################################################################### ++# Install target related stuff ++############################################################################################### ++install(TARGETS ${APPLICATION_NAME} DESTINATION ${BIN_INSTALL_DIR}) ++ ++if (UNIX AND NOT WIN32 AND NOT APPLE) ++ install(FILES ${${APPLICATION_NAME}_QM_FILES} DESTINATION ${DATA_INSTALL_PREFIX}/${APPLICATION_NAME}/translations) ++ install(FILES ${${APPLICATION_NAME}_DESKTOP_FILES} DESTINATION ${XDG_APPS_DIR}) ++endif (UNIX AND NOT WIN32 AND NOT APPLE) +diff --git a/src/qmt_rgb2pct/README.md b/src/qmt_rgb2pct/README.md +new file mode 100644 +index 00000000..21e6c750 +--- /dev/null ++++ b/src/qmt_rgb2pct/README.md +@@ -0,0 +1,5 @@ ++This is a sub-project of QMapShack and it's not supposed to compile on it's own. Please refere to ++ ++https://bitbucket.org/maproom/qmapshack/overview ++ ++to check out and compile this project. +\ No newline at end of file +diff --git a/src/qmt_rgb2pct/locale/qmt_rgb2pct.ts b/src/qmt_rgb2pct/locale/qmt_rgb2pct.ts +new file mode 100644 +index 00000000..02904577 +--- /dev/null ++++ b/src/qmt_rgb2pct/locale/qmt_rgb2pct.ts +@@ -0,0 +1,126 @@ ++ ++ ++ ++ ++ CApp ++ ++ ++ Failed to open source file. ++ ++ ++ ++ ++ Raster band count of source file must be either 3 or 4. ++ ++ ++ ++ ++ Calculate optimal color table from source file ++ ++ ++ ++ ++ Failed to create color table. ++ ++ ++ ++ ++ Failed to open file with palette. ++ ++ ++ ++ ++ Palette file does not have a single band with a color table ++ ++ ++ ++ ++ The color table must not contain a "no data" value and it's size must not exceed 255 colors. ++ ++ ++ ++ ++ Save color table to: %1 ++ ++ ++ ++ ++ Failed to create target file. ++ ++ ++ ++ ++ Dither source file to target file ++ ++ ++ ++ ++ Failed to dither file. ++ ++ ++ ++ ++ Apply alpha channel as no data value to target file ++ ++ ++ ++ ++ Failed to read from alpha channel. ++ ++ ++ ++ ++ Failed to read from target file. ++ ++ ++ ++ ++ Failed to write to target file. ++ ++ ++ ++ ++ main ++ ++ ++ ++Convert a map file with RGBA color coding to a color palette coding. ++ ++ ++ ++ ++ Source file. ++ ++ ++ ++ ++ Target file. ++ ++ ++ ++ ++ Number of colors. (default: 255) ++ ++ ++ ++ ++ Input palette file for color table (*.vrt) ++ ++ ++ ++ ++ Save color table to palette file (*.vrt) ++ ++ ++ ++ ++ There must be a source and destination file. ++ ++ ++ ++ ++ --ncolors must be an integer value less than 256 ++ ++ ++ ++ +diff --git a/src/qmt_rgb2pct/locale/qmt_rgb2pct_de.ts b/src/qmt_rgb2pct/locale/qmt_rgb2pct_de.ts +new file mode 100644 +index 00000000..9622b8d9 +--- /dev/null ++++ b/src/qmt_rgb2pct/locale/qmt_rgb2pct_de.ts +@@ -0,0 +1,127 @@ ++ ++ ++ ++ ++ CApp ++ ++ ++ Failed to open source file. ++ Konnte Quelldatei nicht öffnen. ++ ++ ++ ++ Raster band count of source file must be either 3 or 4. ++ Die Anzahl der Rasterbänder muss entweder 3 oder 4 sein. ++ ++ ++ ++ Calculate optimal color table from source file ++ Berechne die optimale Farbtabelle für die Quelldatei ++ ++ ++ ++ Failed to create color table. ++ Konnte die Farbtabelle nicht erstellen. ++ ++ ++ ++ Failed to open file with palette. ++ Konnte die Datei mit der Palette nicht öffnen. ++ ++ ++ ++ Palette file does not have a single band with a color table ++ Die Datei mit der Palette hat kein einzelnes Band mit einer Farbtabelle ++ ++ ++ ++ The color table must not contain a "no data" value and it's size must not exceed 255 colors. ++ Die Farbtabelle darf keinen Eintrag für "no data" haben und ihre Größe darf nicht 255 Farben überschreiten. ++ ++ ++ ++ Save color table to: %1 ++ Speichere Farbtabelle in: %1 ++ ++ ++ ++ Failed to create target file. ++ Konnte Zieldatei nicht erstellen. ++ ++ ++ ++ Dither source file to target file ++ Wandle Quelldatei in Zieldatei um ++ ++ ++ ++ Failed to dither file. ++ Konnte die Datei nicht umwandeln. ++ ++ ++ ++ Apply alpha channel as no data value to target file ++ Wandle für die Zieldatei den Alphakanal in "no data" Werte um ++ ++ ++ ++ Failed to read from alpha channel. ++ Konnte den Alphakanal nicht lesen. ++ ++ ++ ++ Failed to read from target file. ++ Konnte die Zieldatei nicht lesen. ++ ++ ++ ++ Failed to write to target file. ++ Konnte die Zieldatei nicht schreiben. ++ ++ ++ ++ main ++ ++ ++ ++Convert a map file with RGBA color coding to a color palette coding. ++ ++Konvertiert eine Kartendatei mit RGBA Farbschema in eine Kartendatei mit Farbtabelle. ++ ++ ++ ++ Source file. ++ Quelldatei. ++ ++ ++ ++ Target file. ++ Zieldatei. ++ ++ ++ ++ Number of colors. (default: 255) ++ Anzahl an Farben (Vorgabe: 255) ++ ++ ++ ++ Input palette file for color table (*.vrt) ++ Datei mit Palette als Vorgabe für die Farbtabelle (*.vrt) ++ ++ ++ ++ Save color table to palette file (*.vrt) ++ Farbtabelle in Datei mit Palette sichern (*.vrt) ++ ++ ++ ++ There must be a source and destination file. ++ Es muss eine Quell- und eine Zieldatei angegeben werden. ++ ++ ++ ++ --ncolors must be an integer value less than 256 ++ --ncolors muss eine ganze Zahl kleiner 256 sein ++ ++ ++ +diff --git a/src/qmt_rgb2pct/main.cpp b/src/qmt_rgb2pct/main.cpp +new file mode 100644 +index 00000000..4ff9a9ae +--- /dev/null ++++ b/src/qmt_rgb2pct/main.cpp +@@ -0,0 +1,155 @@ ++/********************************************************************************************** ++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#include "CApp.h" ++#include "version.h" ++#include ++ ++#ifdef Q_OS_MACOS ++static QDir getApplicationDir(QString subdir) ++{ ++ QDir appDir(QCoreApplication::applicationDirPath()); ++ appDir.cdUp(); ++ appDir.cd(subdir); ++ return appDir; ++} ++#endif ++static void prepareTranslator(QString translationPath, QString translationPrefix) ++{ ++ QString locale = QLocale::system().name(); ++ QDir dir(translationPath); ++ if(!QFile::exists(dir.absoluteFilePath(translationPrefix + locale))) ++ { ++ locale = locale.left(2); ++ } ++ ++ QCoreApplication* app = (QCoreApplication*) QCoreApplication::instance(); ++ QTranslator *qtTranslator = new QTranslator(app); ++ ++ if (qtTranslator->load(translationPrefix + locale, translationPath)) ++ { ++ app->installTranslator(qtTranslator); ++ } ++} ++ ++static void loadTranslations() ++{ ++#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(__FreeBSD_kernel__) || defined(__GNU__) || defined(Q_OS_CYGWIN) ++ QString resourceDir = QLibraryInfo::location(QLibraryInfo::TranslationsPath); ++ QString translationPath = QCoreApplication::applicationDirPath(); ++ translationPath.replace(QRegExp("bin$"), "share/" APP_STR "/translations"); ++ prepareTranslator(resourceDir, "qt_"); ++ prepareTranslator(translationPath, APP_STR "_"); ++#endif ++ ++#ifdef Q_OS_OSX ++ // os x ++ static QString relTranslationDir = "Resources/translations"; // app ++ QString translationPath = getApplicationDir(relTranslationDir).absolutePath(); ++ prepareTranslator(translationPath, "qt_"); ++ prepareTranslator(translationPath, APP_STR "_"); ++#endif ++ ++#ifdef Q_OS_WIN ++ QString apppath = QCoreApplication::applicationDirPath(); ++ apppath = apppath.replace("/", "\\"); ++ QString appResourceDir = QString("%1\\translations").arg(apppath).toUtf8(); ++ prepareTranslator(appResourceDir, "qtbase_"); ++ prepareTranslator(appResourceDir, APP_STR "_"); ++#endif ++ ++} ++ ++int main(int argc, char ** argv) ++{ ++ QCoreApplication app(argc, argv); ++ QCoreApplication::setApplicationName(APP_STR); ++ QCoreApplication::setApplicationVersion(VER_STR); ++ if(QString(VER_SUFFIX).isEmpty()) ++ { ++ QCoreApplication::setApplicationVersion(VER_STR); ++ } ++ else ++ { ++ QCoreApplication::setApplicationVersion(VER_STR "." VER_SUFFIX); ++ } ++ ++ ++ loadTranslations(); ++ ++ QCommandLineParser parser; ++ parser.setApplicationDescription(QCoreApplication::translate("main", "\nConvert a map file with RGBA color coding to a color palette coding.")); ++ parser.addHelpOption(); ++ parser.addVersionOption(); ++ parser.addPositionalArgument("source", QCoreApplication::translate("main", "Source file.")); ++ parser.addPositionalArgument("target", QCoreApplication::translate("main", "Target file.")); ++ ++ parser.addOptions({ ++ { ++ {"n","ncolors"}, QCoreApplication::translate("main", "Number of colors. (default: 255)"), "number", "255" ++ }, ++ { ++ {"p","pct"}, QCoreApplication::translate("main", "Input palette file for color table (*.vrt)"), "filename", "" ++ }, ++ { ++ {"s","sct"}, QCoreApplication::translate("main", "Save color table to palette file (*.vrt)"), "filename", "" ++ }, ++ }); ++ ++ // Process the actual command line arguments given by the user ++ parser.process(app); ++ ++ if(parser.positionalArguments().count() == 1 && parser.value("sct").isEmpty()) ++ { ++ printStderrQString(""); ++ printStderrQString(QCoreApplication::translate("main","There must be a source and destination file.")); ++ printStderrQString(""); ++ parser.showHelp(-1); ++ } ++ ++ if(parser.positionalArguments().isEmpty()) ++ { ++ parser.showHelp(-1); ++ } ++ ++ QString srcFilename = parser.positionalArguments()[0]; ++ QString tarFilename; ++ if(parser.positionalArguments().count() > 1) ++ { ++ tarFilename = parser.positionalArguments()[1]; ++ } ++ ++ ++ bool ok = false; ++ const qint32 ncolors = parser.value("ncolors").toInt(&ok); ++ if(!ok || ncolors > 255) ++ { ++ printStderrQString(""); ++ printStderrQString(QCoreApplication::translate("main","--ncolors must be an integer value less than 256")); ++ printStderrQString(""); ++ parser.showHelp(-1); ++ } ++ ++ QString pctFilename = parser.value("pct"); ++ QString sctFilename = parser.value("sct"); ++ ++ CApp theApp(ncolors, pctFilename, sctFilename, srcFilename, tarFilename); ++ return theApp.exec(); ++} ++ ++ +diff --git a/src/qmt_rgb2pct/version.h b/src/qmt_rgb2pct/version.h +new file mode 100644 +index 00000000..60f94f71 +--- /dev/null ++++ b/src/qmt_rgb2pct/version.h +@@ -0,0 +1,33 @@ ++/********************************************************************************************** ++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++**********************************************************************************************/ ++ ++#ifndef VERSION_H ++#define VERSION_H ++ ++#ifndef _MKSTR_1 ++#define _MKSTR_1(x) #x ++#define _MKSTR(x) _MKSTR_1(x) ++#endif ++ ++#define VER_STR _MKSTR(VER_MAJOR) "." _MKSTR (VER_MINOR) "." _MKSTR (VER_STEP) ++#define VER_SUFFIX _MKSTR(VER_TWEAK) ++#define APP_STR _MKSTR(APPLICATION_NAME) ++#define WHAT_STR _MKSTR(APPLICATION_NAME) ", Version " VER_STR ++ ++#endif //VERSION_H ++ diff --git a/gis/qmapshack/splash.png b/gis/qmapshack/splash.png new file mode 100644 index 0000000000000..8a58d5d28eb53 Binary files /dev/null and b/gis/qmapshack/splash.png differ -- cgit v1.2.3