diff --git a/3rd-party/gdal/CMakeLists.txt b/3rd-party/gdal/CMakeLists.txt new file mode 100644 index 000000000..e49aaaf7b --- /dev/null +++ b/3rd-party/gdal/CMakeLists.txt @@ -0,0 +1,209 @@ +# +# Copyright 2016 Kai Pastor +# +# This file is part of OpenOrienteering. +# +# OpenOrienteering 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. +# +# OpenOrienteering 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 OpenOrienteering. If not, see . + + +project(GDAL) + +cmake_minimum_required(VERSION 2.8.3) + +include(ExternalProject) + +# Configuration options + +set(GDAL_VERSION_DEFAULT 2.0.1+dfsg) +set(GDAL_VERSION ${GDAL_VERSION_DEFAULT} CACHE STRING + "Version number of the GDAL library, recommended value: ${GDAL_VERSION_DEFAULT}") +mark_as_advanced(GDAL_VERSION) + +message(STATUS "Configuring GDAL library ${GDAL_VERSION}") + +string(REGEX MATCH "^[0-9]\\.[0-9]+\\.[0-9]+" GDAL_MAJOR_MINOR_REVISION ${GDAL_VERSION}) +if (NOT "${GDAL_VERSION}" MATCHES "^${GDAL_MAJOR_MINOR_REVISION}") + message(WARNING + "The GDAL library version is different from the current recommended version " + "(${GDAL_VERSION} vs. ${GDAL_VERSION_DEFAULT}).") +endif() + +set(GDAL_MD5SUMS + 2.0.1+dfsg:18e207a12f920e2a40405891eb6168ec:https://github.com/OpenOrienteering/sources/releases/download/3rd-party/gdal_2.0.1.dfsg.orig.tar.gz +) +string(REPLACE "+" "[+]" GDAL_VERSION_REGEX "${GDAL_VERSION}") +foreach(line ${GDAL_MD5SUMS}) + if(${line} MATCHES "^${GDAL_VERSION_REGEX}:") + string(REPLACE "${GDAL_VERSION}:" "" GDAL_MD5 ${line}) + break() + endif() +endforeach() +if(NOT GDAL_MD5) + message(FATAL_ERROR + "Unknown MD5 sum for GDAL library ${GDAL_VERSION}. " + "Edit ${GDALECT_SOURCE_DIR}/CMakeLists.txt, " + "or specify the correct GDAL_MD5 value at the command line.") +endif() +if(GDAL_MD5 MATCHES ":") + message(WARNING "Not using an official release of GDAL.") + string(REGEX REPLACE "^[0-9a-fA-F]*:" "" GDAL_URL "${GDAL_MD5}") + string(REGEX REPLACE ":.*" "" GDAL_MD5 "${GDAL_MD5}") +elseif(GDAL_VERSION MATCHES "-openorienteering-") + set(GDAL_URL "https://github.com/OpenOrienteering/sources/releases/download/3rd-party/gdal-${GDAL_VERSION}.tar.gz") +else() + set(GDAL_URL "http://download.osgeo.org/gdal/${GDAL_VERSION}/gdal-${GDAL_VERSION}.tar.gz") +endif() + +set(GDAL_LICENSE_FILE "${PROJECT_SOURCE_DIR}/LICENSE.TXT") +if(EXISTS "${GDAL_LICENSE_FILE}.${GDAL_VERSION}") + set(GDAL_LICENSE_FILE "${GDAL_LICENSE_FILE}.${GDAL_VERSION}") +endif() + + +# External project definition + +set(GDAL_EXTRA_FLAGS "-Wno-unused-parameter -Wno-ignored-qualifiers -Wno-unused-private-field -Wno-deprecated-register") +string(REGEX REPLACE "-Wpedantic|-Wall" "" GDAL_CFLAGS "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_RELEASE} ${GDAL_EXTRA_FLAGS}") +string(REGEX REPLACE "-Wpedantic|-Wall" "" GDAL_CXXFLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELEASE} ${GDAL_EXTRA_FLAGS}") +if(CMAKE_CROSSCOMPILING AND NOT GNU_SYSTEM_NAME AND MINGW) + set(_env_lang $ENV{LC_ALL}) + set(ENV{LC_ALL} C) + execute_process( + COMMAND ${CMAKE_C_COMPILER} -v + ERROR_VARIABLE GNU_SYSTEM_NAME + ) + set(ENV{LC_ALL} ${_env_lang}) + string(REGEX REPLACE ".*Target: ?([^\n]*).*" \\1 GNU_SYSTEM_NAME ${GNU_SYSTEM_NAME}) +endif() +if(CMAKE_CROSSCOMPILING AND GNU_SYSTEM_NAME) + execute_process( + COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/patches/config.guess" + OUTPUT_VARIABLE build + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + set(GDAL_CONFIG_EXTRA "--host=${GNU_SYSTEM_NAME}" "--build=${build}" --without-expat) + get_directory_property(_include_dirs INCLUDE_DIRECTORIES) + if(_include_dirs) + unset(_cpp_flags) + foreach(_dir ${_include_dirs}) + set(_cpp_flags "${_cpp_flags} -I${_dir}") + endforeach() + list(APPEND GDAL_CONFIG_EXTRA "CPPFLAGS=${_cpp_flags}") + endif() + if(GNU_SYSTEM_NAME STREQUAL "arm-linux-androideabi") + set(STANDALONE_TOOLCHAIN arm-linux-androideabi-4.9) + set(CMAKE_C_COMPILER /toolchain/${STANDALONE_TOOLCHAIN}/bin/arm-linux-androideabi-gcc) + set(CMAKE_CXX_COMPILER /toolchain/${STANDALONE_TOOLCHAIN}/bin/arm-linux-androideabi-g++) + elseif(GNU_SYSTEM_NAME STREQUAL "i686-linux-android") + set(STANDALONE_TOOLCHAIN arm-linux-androideabi-gcc-4.9) + set(CMAKE_C_COMPILER /toolchain/${STANDALONE_TOOLCHAIN}/bin/i686-linux-android-gcc) + set(CMAKE_CXX_COMPILER /toolchain/${STANDALONE_TOOLCHAIN}/bin/i686-linux-android-g++) + elseif(ANDROID) + message(WARNING "Unsupported Android architecture '${GNU_SYSTEM_NAME}'") + endif() +elseif(APPLE) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++") + # Didn't manage to pass the deployment target to all libtool link steps + #string(REGEX REPLACE "(^| )(--?[^W])" "\\1-Wl,\\2" CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS}) + set(GDAL_CONFIG_EXTRA --without-libtool) +else() + unset(GDAL_CONFIG_EXTRA) +endif() + +include(ExternalProject) +ExternalProject_Add( + GDAL + DOWNLOAD_DIR ${PROJECT_SOURCE_DIR}/download + URL ${GDAL_URL} + URL_MD5 ${GDAL_MD5} + # Check that the license hasn't changed. + UPDATE_COMMAND + ${CMAKE_COMMAND} -E compare_files /LICENSE.TXT "${GDAL_LICENSE_FILE}" + PATCH_COMMAND + cp ${PROJECT_SOURCE_DIR}/patches/config.sub ${PROJECT_SOURCE_DIR}/patches/config.guess / + COMMAND + find ${PROJECT_SOURCE_DIR}/patches -name gdal-${GDAL_MAJOR_MINOR_REVISION}*.patch -exec patch -p0 -N -i {} + + CONFIGURE_COMMAND + "/configure" + "--prefix=" + --disable-static + --enable-shared + --with-ogr + --with-hide-internal-symbols + --with-rename-internal-libtiff-symbols + --without-jpeg12 # possible violation of ODR in GDAL < 2.1 + --with-threads=no + --without-pcraster + --without-grib + --without-perl + --without-php + --without-python + --without-java + ${GDAL_CONFIG_EXTRA} + "CC=${CMAKE_C_COMPILER}" + "CFLAGS=${GDAL_CFLAGS}" + "CXX=${CMAKE_CXX_COMPILER}" + "CXXFLAGS=${GDAL_CXXFLAGS}" + "LDFLAGS=${CMAKE_EXE_LINKER_FLAGS}" + BUILD_COMMAND + "\$(MAKE)" + INSTALL_COMMAND + "\$(MAKE)" -j1 install + BUILD_IN_SOURCE 1 +) + +if(ANDROID AND STANDALONE_TOOLCHAIN) + ExternalProject_Add_Step(GDAL toolchain + COMMENT "Creating standalone toolchain" + DEPENDEES update + DEPENDERS configure + COMMAND + bash $(ANDROID_NDK_ROOT)/build/tools/make-standalone-toolchain.sh + --install-dir=/toolchain/${STANDALONE_TOOLCHAIN} + --platform=$(ANDROID_NDK_PLATFORM) + --toolchain=${STANDALONE_TOOLCHAIN} + ) +endif() + + +# Exported configuration + +# The following will not succeed during the initial configuration +# but on repeated configuration after an successful build. + +ExternalProject_Get_Property(GDAL BINARY_DIR) +ExternalProject_Get_Property(GDAL INSTALL_DIR) + +find_path(GDAL_INCLUDE_DIR NAMES gdal.h PATHS + "${INSTALL_DIR}/include" + NO_DEFAULT_PATH + NO_CMAKE_FIND_ROOT_PATH +) +mark_as_advanced(GDAL_INCLUDE_DIR) + +find_library(GDAL_LIBRARY NAMES gdal PATHS + "${INSTALL_DIR}/lib" + NO_DEFAULT_PATH + NO_CMAKE_FIND_ROOT_PATH +) +mark_as_advanced(GDAL_LIBRARY) + +if(GDAL_INCLUDE_DIR AND GDAL_LIBRARY) + set(GDAL_BINARY_DIR "${INSTALL_DIR}/bin" PARENT_SCOPE) + mark_as_advanced(GDAL_BINARY_DIR) + set(GDAL_FOUND TRUE PARENT_SCOPE) +endif() + +# Don't let Xcode re-root the install +set_target_properties(GDAL PROPERTIES XCODE_ATTRIBUTE_INSTALL_ROOT "") diff --git a/3rd-party/gdal/LICENSE.TXT b/3rd-party/gdal/LICENSE.TXT new file mode 100644 index 000000000..d65fdd241 --- /dev/null +++ b/3rd-party/gdal/LICENSE.TXT @@ -0,0 +1,263 @@ + +GDAL/OGR Licensing +================== + +This file attempts to include all licenses that apply within the GDAL/OGR +source tree, in particular any that are supposed to be exposed to the end user +for credit requirements for instance. The contents of this file can be +displayed from GDAL commandline utilities using the --license commandline +switch. + + +GDAL/OGR General +---------------- + +In general GDAL/OGR is licensed under an MIT/X style license with the +following terms: + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + + +gdal/frmts/gtiff/tif_float.c +---------------------------- + +Copyright (c) 2002, Industrial Light & Magic, a division of Lucas +Digital Ltd. LLC + +All rights reserved. + +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. +* Neither the name of Industrial Light & Magic nor the names of +its contributors may be used to endorse or promote products derived +from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT +OWNER 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. + + +gdal/frmts/hdf4/hdf-eos/* +------------------------ + + Copyright (C) 1996 Hughes and Applied Research Corporation + + Permission to use, modify, and distribute this software and its documentation + for any purpose without fee is hereby granted, provided that the above + copyright notice appear in all copies and that both that copyright notice and + this permission notice appear in supporting documentation. + + +gdal/frmts/pcraster/libcsf +-------------------------- + +Copyright (c) 1997-2003, Utrecht University +All rights reserved. + +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. + +* Neither the name of Utrecht University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT +OWNER 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. + +gdal/frmts/grib/degrib/* +------------------------ + +The degrib and g2clib source code are modified versions of code produced +by NOAA NWS and are in the public domain subject to the following +restrictions: + +http://www.weather.gov/im/softa.htm + +DISCLAIMER The United States Government makes no warranty, expressed or +implied, as to the usefulness of the software and documentation for any +purpose. The U.S. Government, its instrumentalities, officers, employees, +and agents assumes no responsibility (1) for the use of the software and +documentation listed below, or (2) to provide technical support to users. + +http://www.weather.gov/disclaimer.php + + The information on government servers are in the public domain, unless +specifically annotated otherwise, and may be used freely by the public so +long as you do not 1) claim it is your own (e.g. by claiming copyright for +NWS information -- see below), 2) use it in a manner that implies an +endorsement or affiliation with NOAA/NWS, or 3) modify it in content and +then present it as official government material. You also cannot present +information of your own in a way that makes it appear to be official +government information.. + + The user assumes the entire risk related to its use of this data. NWS is +providing this data "as is," and NWS disclaims any and all warranties, +whether express or implied, including (without limitation) any implied +warranties of merchantability or fitness for a particular purpose. In no +event will NWS be liable to you or to any third party for any direct, +indirect, incidental, consequential, special or exemplary damages or lost +profit resulting from any use or misuse of this data. + + As required by 17 U.S.C. 403, third parties producing copyrighted works +consisting predominantly of the material appearing in NWS Web pages must +provide notice with such work(s) identifying the NWS material incorporated +and stating that such material is not subject to copyright protection. + +port/cpl_minizip* +----------------- + +This is version 2005-Feb-10 of the Info-ZIP copyright and license. +The definitive version of this document should be available at +ftp://ftp.info-zip.org/pub/infozip/license.html indefinitely. + + +Copyright (c) 1990-2005 Info-ZIP. All rights reserved. + +For the purposes of this copyright and license, "Info-ZIP" is defined as +the following set of individuals: + + Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois, + Jean-loup Gailly, Hunter Goatley, Ed Gordon, Ian Gorman, Chris Herborth, + Dirk Haase, Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz, + David Kirschbaum, Johnny Lee, Onno van der Linden, Igor Mandrichenko, + Steve P. Miller, Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs, + Kai Uwe Rommel, Steve Salisbury, Dave Smith, Steven M. Schweda, + Christian Spieler, Cosmin Truta, Antoine Verheijen, Paul von Behren, + Rich Wales, Mike White + +This software is provided "as is," without warranty of any kind, express +or implied. In no event shall Info-ZIP or its contributors be held liable +for any direct, indirect, incidental, special or consequential damages +arising out of the use of or inability to use this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. Redistributions of source code must retain the above copyright notice, + definition, disclaimer, and this list of conditions. + + 2. Redistributions in binary form (compiled executables) must reproduce + the above copyright notice, definition, disclaimer, and this list of + conditions in documentation and/or other materials provided with the + distribution. The sole exception to this condition is redistribution + of a standard UnZipSFX binary (including SFXWiz) as part of a + self-extracting archive; that is permitted without inclusion of this + license, as long as the normal SFX banner has not been removed from + the binary or disabled. + + 3. Altered versions--including, but not limited to, ports to new operating + systems, existing ports with new graphical interfaces, and dynamic, + shared, or static library versions--must be plainly marked as such + and must not be misrepresented as being the original source. Such + altered versions also must not be misrepresented as being Info-ZIP + releases--including, but not limited to, labeling of the altered + versions with the names "Info-ZIP" (or any variation thereof, including, + but not limited to, different capitalizations), "Pocket UnZip," "WiZ" + or "MacZip" without the explicit permission of Info-ZIP. Such altered + versions are further prohibited from misrepresentative use of the + Zip-Bugs or Info-ZIP e-mail addresses or of the Info-ZIP URL(s). + + 4. Info-ZIP retains the right to use the names "Info-ZIP," "Zip," "UnZip," + "UnZipSFX," "WiZ," "Pocket UnZip," "Pocket Zip," and "MacZip" for its + own source and binary releases. + + +gdal/ogr/ogrsf_frmts/dxf/intronurbs.cpp +--------------------------------------- + +This code is derived from the code associated with the book "An Introduction +to NURBS" by David F. Rogers. More information on the book and the code is +available at: + + http://www.nar-associates.com/nurbs/ + + +Copyright (c) 2009, David F. Rogers +All rights reserved. + +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. + * Neither the name of the David F. Rogers nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. + +gdal/alg/thinplatespline.cpp +---------------------------- + +IEEE754 log() code derived from: +@(#)e_log.c 1.3 95/01/18 + +Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + +Developed at SunSoft, a Sun Microsystems, Inc. business. +Permission to use, copy, modify, and distribute this +software is freely granted, provided that this notice +is preserved. diff --git a/3rd-party/gdal/download/README.txt b/3rd-party/gdal/download/README.txt new file mode 100644 index 000000000..dccca3541 --- /dev/null +++ b/3rd-party/gdal/download/README.txt @@ -0,0 +1 @@ +This directory contains downloaded GDAL source archives. diff --git a/3rd-party/gdal/gdal.pro b/3rd-party/gdal/gdal.pro new file mode 100644 index 000000000..37aab9e6a --- /dev/null +++ b/3rd-party/gdal/gdal.pro @@ -0,0 +1,69 @@ +# +# Copyright 2016 Kai Pastor +# +# This file is part of OpenOrienteering. +# +# OpenOrienteering 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. +# +# OpenOrienteering 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 OpenOrienteering. If not, see . + +TEMPLATE = aux +CONFIG -= debug_and_release + +CMAKE_TOOLCHAIN_FILE = $$clean_path($$OUT_PWD/../../toolchain.cmake) +if (exists($$CMAKE_TOOLCHAIN_FILE)) { + CMAKE_ARGS += "-DCMAKE_TOOLCHAIN_FILE=\"$$CMAKE_TOOLCHAIN_FILE\"" + gdal.depends += $$CMAKE_TOOLCHAIN_FILE +} + +gdal.dir = $$OUT_PWD/gdal +gdal.target = $$gdal.dir/GDAL-prefix/lib/libgdal.so +osx: gdal.target = $$gdal.dir/GDAL-prefix/lib/libgdal.dylib +win32: gdal.target = $$gdal.dir/GDAL-prefix/bin/libgdal-20.dll +gdal.cflags = $$QMAKE_CFLAGS -Wno-declaration-after-statement -Wno-int-to-pointer-cast +gdal.commands = \ + mkdir -p "$$gdal.dir" && \ + cd "$$gdal.dir" && \ + if [ -d CMakeFiles -o -f CMakeCache.txt ] ; then rm -R CMake*; fi && \ + if [ -d GDAL-prefix ] ; then rm -R GDAL-prefix; fi && \ + cmake "$$PWD" $$CMAKE_ARGS && \ + PATH="$$NDK_TOOLCHAIN_PATH/bin:${PATH}" $(MAKE) VERBOSE=$(VERBOSE) all && \ + $(MAKE) clean VERBOSE=$(VERBOSE) + +QMAKE_EXTRA_TARGETS += gdal +PRE_TARGETDEPS += $$gdal.target +QMAKE_CLEAN += $$gdal.target + +GDAL_PRI = \ + "$$LITERAL_HASH Generated by $$_PRO_FILE_" \ + "DEPENDPATH += $$gdal.dir/GDAL-prefix/include" \ + "INCLUDEPATH += $$gdal.dir/GDAL-prefix/include" +win32: GDAL_PRI += \ + "LIBS += \"-L$$gdal.dir/GDAL-prefix/bin\"" +else: GDAL_PRI += \ + "LIBS += \"-L$$gdal.dir/GDAL-prefix/lib\"" +android: GDAL_PRI += \ + "ANDROID_EXTRA_LIBS += \"$$gdal.target\"" + +write_file($$OUT_PWD/gdal.pri, GDAL_PRI) + +android|win32 { + INSTALLS += gdal_data + gdal_data.prefix = + android: gdal_data.prefix = /assets + gdal_data.path = $$gdal_data.prefix/gdal + gdal_data.files = $$gdal.dir/GDAL-prefix/share/gdal/* +} + +OTHER_FILES += \ + CMakeLists.txt \ + LICENSE.TXT diff --git a/3rd-party/gdal/patches/config.guess b/3rd-party/gdal/patches/config.guess new file mode 100755 index 000000000..b79252d6b --- /dev/null +++ b/3rd-party/gdal/patches/config.guess @@ -0,0 +1,1558 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright 1992-2013 Free Software Foundation, Inc. + +timestamp='2013-06-10' + +# This file 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 . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). +# +# Originally written by Per Bothner. +# +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD +# +# Please send patches with a ChangeLog entry to config-patches@gnu.org. + + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright 1992-2013 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +case "${UNAME_SYSTEM}" in +Linux|GNU|GNU/*) + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + LIBC=gnu + + eval $set_cc_for_build + cat <<-EOF > $dummy.c + #include + #if defined(__UCLIBC__) + LIBC=uclibc + #elif defined(__dietlibc__) + LIBC=dietlibc + #else + LIBC=gnu + #endif + EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` + ;; +esac + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm*:riscos:*:*|arm*:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH="i386" + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH="x86_64" + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case ${UNAME_PROCESSOR} in + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW64*:*) + echo ${UNAME_MACHINE}-pc-mingw64 + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:MSYS*:*) + echo ${UNAME_MACHINE}-pc-msys + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + aarch64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC="gnulibc1" ; fi + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arc:Linux:*:* | arceb:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi + else + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf + fi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + cris:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + crisv32:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + frv:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + hexagon:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:Linux:*:*) + echo ${UNAME_MACHINE}-pc-linux-${LIBC} + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } + ;; + or1k:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + or32:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-${LIBC} + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-${LIBC} + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; + PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; + *) echo hppa-unknown-linux-${LIBC} ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-${LIBC} + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-${LIBC} + exit ;; + ppc64le:Linux:*:*) + echo powerpc64le-unknown-linux-${LIBC} + exit ;; + ppcle:Linux:*:*) + echo powerpcle-unknown-linux-${LIBC} + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux-${LIBC} + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + tile*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-${LIBC} + exit ;; + x86_64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + x86_64:Haiku:*:*) + echo x86_64-unknown-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + eval $set_cc_for_build + if test "$UNAME_PROCESSOR" = unknown ; then + UNAME_PROCESSOR=powerpc + fi + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi + fi + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NEO-?:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk${UNAME_RELEASE} + exit ;; + NSE-*:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; + x86_64:VMkernel:*:*) + echo ${UNAME_MACHINE}-unknown-esx + exit ;; +esac + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/3rd-party/gdal/patches/config.sub b/3rd-party/gdal/patches/config.sub new file mode 100755 index 000000000..9633db704 --- /dev/null +++ b/3rd-party/gdal/patches/config.sub @@ -0,0 +1,1791 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright 1992-2013 Free Software Foundation, Inc. + +timestamp='2013-08-10' + +# This file 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 . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). + + +# Please send patches with a ChangeLog entry to config-patches@gnu.org. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright 1992-2013 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ + linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + android-linux) + os=-linux-android + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze*) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*178) + os=-lynxos178 + ;; + -lynx*5) + os=-lynxos5 + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | aarch64 | aarch64_be \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arceb \ + | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ + | avr | avr32 \ + | be32 | be64 \ + | bfin \ + | c4x | c8051 | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | epiphany \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | le32 | le64 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipsr5900 | mipsr5900el \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nds32 | nds32le | nds32be \ + | nios | nios2 | nios2eb | nios2el \ + | ns16k | ns32k \ + | open8 \ + | or1k | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pyramid \ + | rl78 | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu \ + | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | we32k \ + | x86 | xc16x | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + c54x) + basic_machine=tic54x-unknown + ;; + c55x) + basic_machine=tic55x-unknown + ;; + c6x) + basic_machine=tic6x-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + strongarm | thumb | xscale) + basic_machine=arm-unknown + ;; + xgate) + basic_machine=$basic_machine-unknown + os=-none + ;; + xscaleeb) + basic_machine=armeb-unknown + ;; + + xscaleel) + basic_machine=armel-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | aarch64-* | aarch64_be-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | be32-* | be64-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ + | c8051-* | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | hexagon-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | le32-* | le64-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ + | microblaze-* | microblazeel-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipsr5900-* | mipsr5900el-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nds32-* | nds32le-* | nds32be-* \ + | nios-* | nios2-* | nios2eb-* | nios2el-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | open8-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pyramid-* \ + | rl78-* | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ + | tahoe-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tile*-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ + | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c54x-*) + basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c55x-*) + basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c6x-*) + basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16 | cr16-*) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze*) + basic_machine=microblaze-xilinx + ;; + mingw64) + basic_machine=x86_64-pc + os=-mingw64 + ;; + mingw32) + basic_machine=i686-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + msys) + basic_machine=i686-pc + os=-msys + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + nacl) + basic_machine=le32-unknown + os=-nacl + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + neo-tandem) + basic_machine=neo-tandem + ;; + nse-tandem) + basic_machine=nse-tandem + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc | ppcbe) basic_machine=powerpc-unknown + ;; + ppc-* | ppcbe-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + os=-rdos + ;; + rdos32) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + strongarm-* | thumb-*) + basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tile*) + basic_machine=$basic_machine-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + xscale-* | xscalee[bl]-*) + basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* | -plan9* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -bitrig* | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-musl* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -nacl*) + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + c8051-*) + os=-elf + ;; + hexagon-*) + os=-elf + ;; + tic54x-*) + os=-coff + ;; + tic55x-*) + os=-coff + ;; + tic6x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or1k-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/3rd-party/gdal/patches/gdal-2.0.1.patch b/3rd-party/gdal/patches/gdal-2.0.1.patch new file mode 100644 index 000000000..dc69ccb2d --- /dev/null +++ b/3rd-party/gdal/patches/gdal-2.0.1.patch @@ -0,0 +1,24 @@ +diff -up ./frmts/GNUmakefile.orig ./frmts/GNUmakefile +--- ./frmts/GNUmakefile.orig 2016-01-01 22:53:27.597434480 +0100 ++++ ./frmts/GNUmakefile 2016-01-01 22:54:29.020540683 +0100 +@@ -16,7 +16,7 @@ clean: $(foreach d,$(GDAL_FORMATS),$(d)- + $(RM) o/*.lo + + o/gdalallregister.$(OBJ_EXT): gdalallregister.cpp ../GDALmake.opt +- $(CXX) -c $(GDAL_INCLUDE) $(CXXFLAGS) $(FRMT_FLAGS) \ ++ $(CXX) -c $(GDAL_INCLUDE) $(CPPFLAGS) $(CXXFLAGS) $(FRMT_FLAGS) \ + -DGDAL_FORMATS="$(GDAL_FORMATS)" \ + gdalallregister.cpp -o o/gdalallregister.$(OBJ_EXT) + +diff -up ./gcore/GNUmakefile.orig ./gcore/GNUmakefile +--- ./gcore/GNUmakefile.orig 2016-01-01 22:53:17.541580806 +0100 ++++ ./gcore/GNUmakefile 2016-01-01 22:54:06.292871404 +0100 +@@ -48,7 +48,7 @@ docs: + gdal_misc.$(OBJ_EXT): gdal_misc.cpp gdal_version.h + + gdaldrivermanager.$(OBJ_EXT): gdaldrivermanager.cpp ../GDALmake.opt +- $(CXX) -c $(GDAL_INCLUDE) $(CXXFLAGS) -DINST_DATA=\"$(INST_DATA)\" \ ++ $(CXX) -c $(GDAL_INCLUDE) $(CPPFLAGS) $(CXXFLAGS) -DINST_DATA=\"$(INST_DATA)\" \ + $< -o $@ + + install: diff --git a/CMakeLists.txt b/CMakeLists.txt index 49d9b0515..463dfa652 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ # # Copyright 2012, 2013, 2014 Thomas Schöps -# Copyright 2012-2015 Kai Pastor +# Copyright 2012-2016 Kai Pastor # # This file is part of OpenOrienteering. # @@ -35,7 +35,7 @@ set(Mapper_VERSION_MAJOR 0) set(Mapper_VERSION_MINOR 6) if(NOT Mapper_VERSION_PATCH) # This can be configured when running cmake - set(Mapper_VERSION_PATCH 1) + set(Mapper_VERSION_PATCH 2) endif() set(MAPPER_VERSION_PRI "${PROJECT_SOURCE_DIR}/oo-mapper-version.pri") @@ -75,11 +75,13 @@ option(Mapper_DEBUG_TRANSLATIONS "Debug missing translations" OFF) set(Mapper_BUILD_CLIPPER_DEFAULT ON) if(WIN32 OR APPLE) set(Mapper_BUILD_PROJ_DEFAULT ON) + set(Mapper_BUILD_GDAL_DEFAULT ON) set(Mapper_BUILD_QT_DEFAULT ON) set(Mapper_BUILD_DOXYGEN_DEFAULT ON) set(Mapper_BUILD_PACKAGE_DEFAULT ON) else() set(Mapper_BUILD_PROJ_DEFAULT OFF) + set(Mapper_BUILD_GDAL_DEFAULT OFF) set(Mapper_BUILD_QT_DEFAULT ON) set(Mapper_BUILD_DOXYGEN_DEFAULT OFF) set(Mapper_BUILD_PACKAGE_DEFAULT OFF) @@ -89,6 +91,10 @@ option(Mapper_BUILD_CLIPPER "Build the Clipper package from source" ${Mapper_BUI option(Mapper_BUILD_PROJ "Build the Proj library from source" ${Mapper_BUILD_PROJ_DEFAULT}) +option(Mapper_BUILD_GDAL "Build the GDAL library" ${Mapper_BUILD_GDAL_DEFAULT}) + +option(Mapper_USE_GDAL "Use the GDAL library" ${Mapper_BUILD_GDAL}) + option(Mapper_BUILD_QT "Build the Qt library from source" ${Mapper_BUILD_QT_DEFAULT}) option(Mapper_BUILD_DOXYGEN "Build the doxygen tool from source" ${Mapper_BUILD_DOXYGEN_DEFAULT}) @@ -101,12 +107,13 @@ endif() option(Mapper_DEVELOPMENT_BUILD "Configure development build (loading resource from the build directory)" ${Mapper_DEVELOPMENT_BUILD_DEFAULT}) mark_as_advanced(Mapper_DEVELOPMENT_BUILD) -option(Mapper_AUTORUN_UNIT_TESTS "Run the unit tests as part of the default target" ${Mapper_DEVELOPMENT_BUILD}) -option(Mapper_AUTORUN_SYSTEM_TESTS "Run the system tests as part of the default target" OFF) -mark_as_advanced(Mapper_AUTORUN_UNIT_TESTS Mapper_AUTORUN_SYSTEM_TESTS) +option(Mapper_AUTORUN_SYSTEM_TESTS "Run the system tests as part of the Mapper_Test target" ${Mapper_DEVELOPMENT_BUILD}) +option(Mapper_AUTORUN_MANUAL_TESTS "Run the system tests as part of the Mapper_Test target" OFF) +mark_as_advanced(Mapper_AUTORUN_SYSTEM_TESTS Mapper_AUTORUN_MANUAL_TESTS) option(Mapper_BUILD_PACKAGE "Create a target for building packages" ${Mapper_BUILD_PACKAGE_DEFAULT}) option(Mapper_PACKAGE_PROJ "Include all required Proj components in the packages" ${Mapper_BUILD_PROJ}) +option(Mapper_PACKAGE_GDAL "Include all required GDAL components in the packages" ${Mapper_BUILD_GDAL}) option(Mapper_PACKAGE_QT "Include all required Qt components in the packages" ${Mapper_BUILD_QT}) option(Mapper_PACKAGE_ASSISTANT "Include Qt Assistant in the packages" ${Mapper_BUILD_QT}) option(Mapper_PACKAGE_LINGUIST "Build a Qt Linguist package" ${Mapper_BUILD_PACKAGE_DEFAULT}) @@ -203,6 +210,20 @@ else() find_package(Proj REQUIRED) endif() +if(Mapper_BUILD_GDAL) + add_subdirectory(3rd-party/gdal) + add_dependencies(Mapper_prerequisites GDAL) + if(TARGET Proj) + add_dependencies(GDAL Proj) + endif() + if(NOT GDAL_FOUND) + set(Mapper_prerequisites_FOUND FALSE) + endif() + add_feature_info(Mapper_BUILD_GDAL 1 "version: ${GDAL_VERSION}") +elseif(Mapper_USE_GDAL) + find_package(GDAL REQUIRED) +endif() + if(Mapper_BUILD_QT) add_subdirectory(3rd-party/qt5) add_dependencies(Mapper_prerequisites Qt5) @@ -232,6 +253,9 @@ include_directories(${QT_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR} ${PROJ_INCLUDE_DI if(Mapper_DEVELOPMENT_BUILD) add_definitions(-DMAPPER_DEVELOPMENT_BUILD) + include(EnableSanitize) + enable_sanitize(address undefined) + configure_file(suppress.txt.in suppress.txt COPY_ONLY) else() add_definitions(-DQT_NO_DEBUG -DQT_NO_DEBUG_OUTPUT -DQT_NO_WARNING_OUTPUT -DNDEBUG) endif() @@ -251,6 +275,9 @@ add_subdirectory("symbol sets") add_subdirectory("translations") add_subdirectory("3rd-party/qbezier") add_subdirectory("3rd-party/qtsingleapplication") +if (Mapper_USE_GDAL) + add_subdirectory("src/gdal") +endif() add_subdirectory("src/libocad") add_subdirectory("src/printsupport") add_subdirectory("src") diff --git a/INSTALL.md b/INSTALL.md index 4be37010f..feb18f1ef 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -9,19 +9,19 @@ The general build process prerequisites are: - The OpenOrienteering Mapper source code. - CMake >= 2.8.12. CMake is available from http://www.cmake.org/. - - A supported C++ compiler toolchain. + - A supported C++ compiler toolchain. C++11 is mandatory. See below for platform-specific details and build instructions. ## Qt Library -This program uses the Qt library from http://qt-project.org which is released +This program uses the Qt library from http://www.qt.io which is released under the terms of the GNU General Public License, Version 3. -The program is known to work with 5.2 and not to compile with -Qt 4.8 or earlier. Qt 5.5.1 is the recommended version. By default CMake build -settings for OS X and Windows, a special OpenOrienteering source package of -Qt 5.5.1 will be downloaded and built as part of the build process. +The program needs at least Qt 5.2. Qt 5.5.1 is the recommended version. +By default CMake build settings for OS X and Windows, +a special OpenOrienteering source package of Qt 5.5.1 will be downloaded +and built as part of the build process. You can change the cmake option `Mapper_BUILD_QT` to adjust this. @@ -42,7 +42,7 @@ You can change the cmake option `Mapper_BUILD_CLIPPER` to adjust this. The program uses the PROJ.4 Cartographic Projections Library from http://trac.osgeo.org/proj/ which is released under permissive license terms. The program is known to work with the releases 4.8.0 (as contained in Ubuntu -14.04), 4.9.1 and 4.9.2. By default build settings, proj 4.8.0 will be +14.04), 4.9.1 and 4.9.2. By default build settings, proj 4.9.2 will be downloaded and built as part of the build process. On Linux, default settings will use the installed proj library. You can change the cmake option `Mapper_BUILD_PROJ` to adjust this. @@ -69,11 +69,13 @@ source directory (`SOURCE_DIR`). The standard g++ compiler from a recent distribution should work. The Ubuntu 14.04 g++ is known to work. Make sure that the development packages of the -PROJ.4 library and of CUPS are installed. For a Ubuntu or Debian system, installlibproj-dev and libcups2-dev. +PROJ.4 library and of CUPS are installed. For a Ubuntu or Debian system, install +`libproj-dev` and `libcups2-dev`. + To create a DEB package from CMake, fakeroot must be installed. For using the Qt libraries provided by the repositories, the following packages need to be installed: -`qt5-default` (>= 5), `qttools5-dev`, `qttools5-dev-tools`, `libqt5sql5-sqlite` +`qt5-default` (>= 5.2), `qttools5-dev`, `qttools5-dev-tools`, `libqt5sql5-sqlite` Open a terminal, and create a build directory, e.g. as subdirectory build in the source directory, and change to that directory. From the build directory, @@ -128,7 +130,7 @@ make package Some linux distributions may offer cross compiler packages based on MinGW or MinGW-w64 (for Ubuntu: g++-mingw-w64 et al.), and even NSIS/makensis is -available. +available. MXE.cc provides an alternative cross-compilation environment For MinGW-w64 i686 (32 bit) builds, configure the build with @@ -162,7 +164,7 @@ can define different "kits" representing different types of target devices. Qt Creator takes care of switching between debug and release configurations. For setting up the kits, see the Qt Creator documentation: -http://qt-project.org/doc/qtcreator/creator-targets.html +http://doc.qt.io/qtcreator/creator-targets.html Mapper's dependencies, such as the PROJ.4 library, are build by cmake, based on the exisiting CMakeList.txt files and Qt Creator's kit settings. @@ -210,9 +212,15 @@ mkdir build cd build cmake .. -DCMAKE_BUILD_TYPE=Release make -make package ``` +The actual package maybe built by `make package`. However, this is used +(i.e. tested) only for OS X at the moment. +Windows and Linux packages are regularly build on +https://build.opensuse.org/project/show/home:dg0yt, so package recipes for +common distributions can be found there. + + #Speeding up with parallel build jobs The build can make use of multiple processor cores. Add the option diff --git a/README.md b/README.md index 141b01ebb..13651605c 100644 --- a/README.md +++ b/README.md @@ -2,43 +2,52 @@ ![Mapper Screenshot](http://openorienteering.github.io/mapper-manual/pages/images/main_window.png) -OpenOrienteering Mapper is an orienteering mapmaking program and provides a free and open source alternative to existing commercial software. OpenOrienteering Mapper runs on Android, Windows, Mac OS X and Linux. +OpenOrienteering Mapper is an orienteering mapmaking program and provides +a free and open source alternative to existing commercial software. +OpenOrienteering Mapper runs on Android, Windows, Mac OS X and Linux. - - [Manual](http://openorienteering.org/mapper-manual/) + - [Mapper Homepage](http://www.openorienteering.org/apps/mapper/) + - [Manual](http://www.openorienteering.org/mapper-manual/) - [Downloads](https://github.com/OpenOrienteering/mapper/releases) - - [Blog](http://openorienteering.github.io/) + - [OpenOrienteering Blog](http://www.openorienteering.org/) ## Contributing ### Writing Code -For building Mapper from source see [`INSTALL.md`](https://github.com/OpenOrienteering/mapper/blob/master/INSTALL.md). Pull requests are very welcome. +For building Mapper from source see [`INSTALL.md`](https://github.com/OpenOrienteering/mapper/blob/master/INSTALL.md). +Pull requests are very welcome. - - [Ticket system](https://github.com/OpenOrienteering/mapper/issues) - - [API documentation](http://openorienteering.github.io/api-docs/mapper/) - - [Unstable Builds](http://openorienteering.github.io/news/2015/mapper-unstable-packages/) - - [Developer mailing list](https://lists.sourceforge.net/lists/listinfo/oorienteering-devel) + - [Issue tracker](https://github.com/OpenOrienteering/mapper/issues) + - [API documentation](http://www.openorienteering.org/api-docs/mapper/) - [Developer wiki](https://github.com/OpenOrienteering/mapper/wiki) ### Translating -The translations for Mapper are stored in `translations/OpenOrienteering_lang.ts`. The easiest way to edit those files is by using [Qt Linguist for translation](http://doc.qt.io/qt-5/linguist-translators.html). The translations can also be edited with any XML editor. +The translations for Mapper are stored in `translations/OpenOrienteering_{LANGUAGE}.ts`. +The best way to edit those files is by using [Qt Linguist for translation](http://doc.qt.io/qt-5/linguist-translators.html). +The translations can also be edited with any XML editor. -Adding a new translation is done by making a new copy of `OpenOrienteering_template.ts` and replacing `template` in the file name with the relevant language code. The new file also has to be added to `translations/CMakeLists.txt`. +Adding a new translation is done by making a new copy of `OpenOrienteering_template.ts` +and replacing `template` in the file name with the matching language code. +The new file also has to be added to `translations/CMakeLists.txt`. -Some strings such as basic buttons and colors has its translation within the Qt Framework, for translating those see [Qt Localization](https://wiki.qt.io/Qt_Localization). +Some strings such as basic buttons and colors get their translation from the +Qt Framework. For translating those see [Qt Localization](https://wiki.qt.io/Qt_Localization). ### Writing Documentation -The Mapper manual lives in its [own repository](https://github.com/OpenOrienteering/mapper-manual) witch contains all information for you to get started. +The Mapper manual lives in its [own repository](https://github.com/OpenOrienteering/mapper-manual) +which contains all information for you to get started. ### Reporting Issues -Issues and possible improvements can be posted to our public [Ticket system](https://github.com/OpenOrienteering/mapper/issues), please make sure you provide all relevant information about your problem or idea. +Issues and possible improvements can be posted to our public [Ticket system](https://github.com/OpenOrienteering/mapper/issues). +Please make sure you provide all relevant information about your problem or idea. ## License diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index a663a2f65..1cba18ba6 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -1,5 +1,5 @@ - + . + + +if(NOT COMMAND check_cxx_compiler_flag) + include(CheckCXXCompilerFlag) +endif() + +macro(enable_sanitize) + foreach(option ${ARGV}) + if (option STREQUAL "NO_RECOVER") + set(full_option "-fno-sanitize-recover=all") + else() + set(full_option "-fsanitize=${option}") + endif() + if(NOT CMAKE_CXX_FLAGS MATCHES "${full_option}") + string(MAKE_C_IDENTIFIER ${option} option_id) + check_cxx_compiler_flag("${full_option}" SANITIZE_${option_id}) + if(SANITIZE_${option_id}) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${full_option}") + endif() + endif() + endforeach() +endmacro() diff --git a/doc/licensing/CMakeLists.txt b/doc/licensing/CMakeLists.txt index 6d431d77a..6eda8cd38 100644 --- a/doc/licensing/CMakeLists.txt +++ b/doc/licensing/CMakeLists.txt @@ -47,6 +47,7 @@ set(LICENSING_SRCS licensing-html.qdocconf licensing.css src/licensing.qdoc + src/gdal-licensing.qdocinc src/qt-licensing.qdocinc src/trademarks.qdocinc src/apache-2.0.qdoc diff --git a/doc/licensing/licensing.pro b/doc/licensing/licensing.pro index 8dec944f0..146685a41 100644 --- a/doc/licensing/licensing.pro +++ b/doc/licensing/licensing.pro @@ -36,6 +36,7 @@ LICENSING_SRCS = \ $$PWD/licensing-html.qdocconf \ $$PWD/licensing.css \ $$PWD/src/licensing.qdoc \ + $$PWD/src/gdal-licensing.qdocinc \ $$PWD/src/qt-licensing.qdocinc \ $$PWD/src/trademarks.qdocinc \ $$PWD/src/apache-2.0.qdoc \ diff --git a/doc/licensing/src/gdal-licensing.qdocinc b/doc/licensing/src/gdal-licensing.qdocinc new file mode 100644 index 000000000..261f2c7f8 --- /dev/null +++ b/doc/licensing/src/gdal-licensing.qdocinc @@ -0,0 +1,268 @@ +\omit +// This file is part of OpenOrienteering. +\endomit + + \note Depending on the actual package, a particular copy of OpenOrienteering Mapper + may not contain code covered by one or more of the licenses listed here. + +In general GDAL/OGR is licensed under an MIT/X style license with the +following terms: + +\quotation +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +\endquotation + + +\section3 gdal/frmts/gtiff/tif_float.c + +\quotation +Copyright (c) 2002, Industrial Light & Magic, a division of Lucas +Digital Ltd. LLC + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: +\list +\li Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. +\li 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. +\li Neither the name of Industrial Light & Magic nor the names of +its contributors may be used to endorse or promote products derived +from this software without specific prior written permission. +\endlist +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT +OWNER 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. +\endquotation + + +\section3 gdal/frmts/hdf4/hdf-eos/* + +\quotation + Copyright (C) 1996 Hughes and Applied Research Corporation + + Permission to use, modify, and distribute this software and its documentation + for any purpose without fee is hereby granted, provided that the above + copyright notice appear in all copies and that both that copyright notice and + this permission notice appear in supporting documentation. +\endquotation + + +\section3 gdal/frmts/pcraster/libcsf + +\quotation +Copyright (c) 1997-2003, Utrecht University +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +\list +\li Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +\li 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. + +\li Neither the name of Utrecht University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. +\endlist +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT +OWNER 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. +\endquotation + + +\section3 gdal/frmts/grib/degrib/* + +The degrib and g2clib source code are modified versions of code produced +by NOAA NWS and are in the public domain subject to the following +restrictions: + +\quotation +http://www.weather.gov/im/softa.htm + +DISCLAIMER The United States Government makes no warranty, expressed or +implied, as to the usefulness of the software and documentation for any +purpose. The U.S. Government, its instrumentalities, officers, employees, +and agents assumes no responsibility (1) for the use of the software and +documentation listed below, or (2) to provide technical support to users. + +http://www.weather.gov/disclaimer.php + + The information on government servers are in the public domain, unless +specifically annotated otherwise, and may be used freely by the public so +long as you do not 1) claim it is your own (e.g. by claiming copyright for +NWS information -- see below), 2) use it in a manner that implies an +endorsement or affiliation with NOAA/NWS, or 3) modify it in content and +then present it as official government material. You also cannot present +information of your own in a way that makes it appear to be official +government information.. + + The user assumes the entire risk related to its use of this data. NWS is +providing this data "as is," and NWS disclaims any and all warranties, +whether express or implied, including (without limitation) any implied +warranties of merchantability or fitness for a particular purpose. In no +event will NWS be liable to you or to any third party for any direct, +indirect, incidental, consequential, special or exemplary damages or lost +profit resulting from any use or misuse of this data. + + As required by 17 U.S.C. 403, third parties producing copyrighted works +consisting predominantly of the material appearing in NWS Web pages must +provide notice with such work(s) identifying the NWS material incorporated +and stating that such material is not subject to copyright protection. +\endquotation + + +\section3 port/cpl_minizip* + +This is version 2005-Feb-10 of the Info-ZIP copyright and license. +The definitive version of this document should be available at +ftp://ftp.info-zip.org/pub/infozip/license.html indefinitely. + +\quotation +Copyright (c) 1990-2005 Info-ZIP. All rights reserved. + +For the purposes of this copyright and license, "Info-ZIP" is defined as +the following set of individuals: + + Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois, + Jean-loup Gailly, Hunter Goatley, Ed Gordon, Ian Gorman, Chris Herborth, + Dirk Haase, Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz, + David Kirschbaum, Johnny Lee, Onno van der Linden, Igor Mandrichenko, + Steve P. Miller, Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs, + Kai Uwe Rommel, Steve Salisbury, Dave Smith, Steven M. Schweda, + Christian Spieler, Cosmin Truta, Antoine Verheijen, Paul von Behren, + Rich Wales, Mike White + +This software is provided "as is," without warranty of any kind, express +or implied. In no event shall Info-ZIP or its contributors be held liable +for any direct, indirect, incidental, special or consequential damages +arising out of the use of or inability to use this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: +\list 1 +\li Redistributions of source code must retain the above copyright notice, + definition, disclaimer, and this list of conditions. + +\li Redistributions in binary form (compiled executables) must reproduce + the above copyright notice, definition, disclaimer, and this list of + conditions in documentation and/or other materials provided with the + distribution. The sole exception to this condition is redistribution + of a standard UnZipSFX binary (including SFXWiz) as part of a + self-extracting archive; that is permitted without inclusion of this + license, as long as the normal SFX banner has not been removed from + the binary or disabled. + +\li Altered versions--including, but not limited to, ports to new operating + systems, existing ports with new graphical interfaces, and dynamic, + shared, or static library versions--must be plainly marked as such + and must not be misrepresented as being the original source. Such + altered versions also must not be misrepresented as being Info-ZIP + releases--including, but not limited to, labeling of the altered + versions with the names "Info-ZIP" (or any variation thereof, including, + but not limited to, different capitalizations), "Pocket UnZip," "WiZ" + or "MacZip" without the explicit permission of Info-ZIP. Such altered + versions are further prohibited from misrepresentative use of the + Zip-Bugs or Info-ZIP e-mail addresses or of the Info-ZIP URL(s). + +\li Info-ZIP retains the right to use the names "Info-ZIP," "Zip," "UnZip," + "UnZipSFX," "WiZ," "Pocket UnZip," "Pocket Zip," and "MacZip" for its + own source and binary releases. +\endlist +\endquotation + + +\section3 gdal/ogr/ogrsf_frmts/dxf/intronurbs.cpp + +This code is derived from the code associated with the book "An Introduction +to NURBS" by David F. Rogers. More information on the book and the code is +available at: + + http://www.nar-associates.com/nurbs/ + +\quotation +Copyright (c) 2009, David F. Rogers +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +\list +\li Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +\li 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. +\li Neither the name of the David F. Rogers nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. +\endlist +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +\endquotation + + +\section3 gdal/alg/thinplatespline.cpp + +IEEE754 log() code derived from: +@(#)e_log.c 1.3 95/01/18 + +\quotation +Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + +Developed at SunSoft, a Sun Microsystems, Inc. business. +Permission to use, copy, modify, and distribute this +software is freely granted, provided that this notice +is preserved. +\endquotation diff --git a/doc/licensing/src/licensing.qdoc b/doc/licensing/src/licensing.qdoc index 9a448365a..869a610f2 100644 --- a/doc/licensing/src/licensing.qdoc +++ b/doc/licensing/src/licensing.qdoc @@ -98,6 +98,16 @@ THE SOFTWARE. \endquotation +\section2 GDAL - Geospatial Data Abstraction Library + +\e {GDAL is an open source X/MIT licensed translator library for raster and + vector geospatial data formats.} +\break +\l http://www.gdal.org/ + +\include gdal-licensing.qdocinc + + \section2 GNU Standard C++ Library v3 \e {The GNU Standard C++ Library v3 is an ongoing project to implement the diff --git a/examples/complete map.omap b/examples/complete map.omap index 3c7b330e1..1a86c98b3 100644 --- a/examples/complete map.omap +++ b/examples/complete map.omap @@ -86,7 +86,7 @@ Competitors violating this rule will be disqualified.</span> The minimum gap between buildings and between buildings and other impassable features shall be 0.40 mm. The black screen percentage should be chosen according to the terrain. A dark screen gives a better contrast to passable areas, such as streets, stairways and canopies, while a light screen makes contours and course overprint more clearly visible (which can be important in very densely built up urban terrain and in steep urban terrain). The black screen shall be the same for the whole map. <span style="color:magenta">It is forbidden to pass through or over a building! -Competitors violating this rule will be disqualified.</span>Do not use this symbol on its own!Do not use this symbol on its own!A building is a relatively permanent construction having a roof. Buildings within symbol area with forbidden access (527.1) may just be represented in a simplified manner.Areas totally contained within a building shall be mapped as being a part of the building. +Competitors violating this rule will be disqualified.</span>Do not use this symbol on its own!Do not use this symbol on its own!A building is a relatively permanent construction having a roof. Buildings within symbol area with forbidden access (527.1) may just be represented in a simplified manner.Areas totally contained within a building shall be mapped as being a part of the building. The minimum gap between buildings and between buildings and other impassable features shall be 0.40 mm. The black screen percentage should be chosen according to the terrain. A dark screen gives a better contrast to passable areas, such as streets, stairways and canopies, while a light screen makes contours and course overprint more clearly visible (which can be important in very densely built up urban terrain and in steep urban terrain). The black screen shall be the same for the whole map. @@ -181,7 +181,7 @@ An out-of-bounds area is shown with vertical stripes. A bounding line may be dra - no line indicates no marking on the ground. <span style="color:magenta">It is forbidden to cross an out-of-bounds area! -Competitors violating this rule will be disqualified.</span>A solid line indicates that the boundary is marked continuously (tapes, etc.) on the ground.A dashed line indicates intermittent marking on the ground.The location of a first aid post.-1500 0;1500 0;0 -1500;0 1500;The location of a refreshment point which is not at a control or along the marked route.-1340 -1395;-820 1380;1340 -1395;820 1380;0 -1770 1;600 -1770;1200 -1620;1340 -1395 1;1200 -1170;600 -1020;0 -1020 1;-600 -1020;-1200 -1170;-1340 -1395 1;-1200 -1620;-600 -1770;0 -1770;-820 1380 1;-680 1680;680 1680;820 1380;Obvious temporary constructions like platforms for spectators and speaker, closed area for spectators, outside restaurant areas, etc. shall be represented in plan shape. +Competitors violating this rule will be disqualified.</span>A solid line indicates that the boundary is marked continuously (tapes, etc.) on the ground.A dashed line indicates intermittent marking on the ground.The location of a first aid post.-1500 0;1500 0;0 -1500;0 1500;The location of a refreshment point which is not at a control or along the marked route.-1340 -1395;-820 1380;1340 -1395;820 1380;0 -1770 1;600 -1770;1200 -1620;1340 -1395 1;1200 -1170;600 -1020;0 -1020 1;-600 -1020;-1200 -1170;-1340 -1395 1;-1200 -1620;-600 -1770;0 -1770;-820 1380 1;-680 1680;680 1680;820 1380;Obvious temporary constructions like platforms for spectators and speaker, closed area for spectators, outside restaurant areas, etc. shall be represented in plan shape. <span style="color:magenta">It is forbidden to enter a temporary construction or closed area! Competitors violating this rule will be disqualified.</span>This symbol provides a simple and quick way to make training courses. @@ -212,4 +212,4 @@ Cultivation boundary; Step Stone; Rock face Well; Small erosion gully --94509 -76769 32;-91828 -76769 32;-91828 -74145 32;-94509 -74145 32;-94509 -76769 50;-94217 -80160 32;-92083 -80160 32;-92083 -78042 32;-94217 -78042 32;-94217 -80160 50;-94509 -62288 32;-91828 -62288 32;-91828 -59664 32;-94509 -59664 32;-94509 -62288 50;-94509 -65897 32;-91828 -65897 32;-91828 -63273 32;-94509 -63273 32;-94509 -65897 50;-93630 -69541;-91828 -69541 32;-91828 -66917 32;-93630 -66917 16;-94509 -33067 32;-91828 -33067 32;-91828 -30443 32;-94509 -30443 32;-94509 -33067 50;-94509 -18612 32;-91828 -18612 32;-91828 -15988 32;-94509 -15988 32;-94509 -18612 50;-94509 -22221 32;-91828 -22221 32;-91828 -19597 32;-94509 -19597 32;-94509 -22221 50;-97187 -69541 32;-95398 -69541 32;-95398 -66917 32;-97187 -66917 32;-97187 -69541 50;-97187 -18612 32;-94506 -18612 32;-94506 -15988 32;-97187 -15988 32;-97187 -18612 50;-96905 -80131 32;-94837 -80131 32;-94837 -78071 32;-96905 -78071 32;-96905 -80131 50;-97187 -33067 32;-94506 -33067 32;-94506 -30443 32;-97187 -30443 32;-97187 -33067 50;-97187 -65897 32;-94506 -65897 32;-94506 -63273 32;-97187 -63273 32;-97187 -65897 50;-97187 -22221 32;-94506 -22221 32;-94506 -19597 32;-97187 -19597 32;-97187 -22221 50;-97187 -76769 32;-94506 -76769 32;-94506 -74145 32;-97187 -74145 32;-97187 -76769 50;-97187 -62288 32;-94506 -62288 32;-94506 -59664 32;-97187 -59664 32;-97187 -62288 50;-95397 -69541 32;-93622 -69541 32;-93622 -66917 32;-95397 -66917 32;-95397 -69541 50;-97186 -70537 32;-97186 -73161 32;-91827 -73161 32;-91827 -70537 32;-97186 -70537 50;-95825 -57271;-93188 -57246;-96926 -52501 1;-96327 -53305;-95862 -53873;-95644 -54852;-95060 -52368 1;-94445 -53213;-94272 -53817;-94000 -54826;-92735 -52616;-92735 -54560;-92735 -52616;-92735 -54560;-97176 -50002;-91837 -50002;-97176 -46314;-91837 -46314;-97176 -42701;-91837 -42701;-97176 -39024;-91837 -39024;-97176 -35418;-91837 -35418;-96856 -27135;-95292 -29044;-95238 -27135;-93674 -29044;-93744 -27135;-92180 -29044;-97015 -24865 1;-96587 -25062;-96095 -25420;-95626 -25727;-97003 -23702 1;-95974 -23917;-95416 -24580;-94390 -24352;-95703 -24177;-93450 -24790 1;-93191 -25215;-92761 -25425;-92488 -25260 1;-92215 -25094;-92204 -24615;-92462 -24190 1;-92721 -23764;-93151 -23554;-93424 -23720 1;-93697 -23885;-93708 -24364;-93450 -24790 18;-97012 -24218 1;-96005 -24698;-95019 -25545;-94318 -25362;-96651 -12597;-95063 -14610;-93963 -12572;-92375 -14585;-95844 -9873;-94070 -8966;-92558 -11017;-95847 -6305;-93964 -5333;-92452 -7384;-97183 -97983 32;-94502 -97983 32;-94502 -95359 32;-97183 -95359 32;-97183 -97983 50;-94505 -97983 32;-91824 -97983 32;-91824 -95359 32;-94505 -95359 32;-94505 -97983 50;-97183 -101608 32;-94502 -101608 32;-94502 -98984 32;-97183 -98984 32;-97183 -101608 50;-94505 -101608 32;-91824 -101608 32;-91824 -98984 32;-94505 -98984 32;-94505 -101608 50;-91824 -101608;-97183 -101608;-97183 -98984;-91824 -98984;-91824 -101608 18;-94724 99498;29307 113498;38500 125237;45571 125803;49531 117317;74846 105013;77816 98932;91676 -31463;87716 -42777;78947 -41363;77816 -34857;72159 -34857;66302 -44060;56502 -43843;52359 -67385;26620 -63708;-47487 -75871;-48878 -61311;-52432 -52082;-86725 72900;-89598 78252;-95147 91437;-94724 99498 18;-87750 85332;-87944 85220;-88019 84989;-88000 84582;-87663 84664;-87700 85032;-87750 85332 18;-51203 55455 32;-49647 55455 32;-49647 60864 32;-51203 60864 32;-51203 55455 50;-50724 14979 32;-50024 14979 32;-50024 15742 32;-50724 15742 32;-50724 14979 50;-50688 1358 32;-50051 1358 32;-50051 -442 32;-50688 -442 32;-50688 1358 50;-13135 -24391 32;-12709 -24391 32;-12709 -8940 32;-13135 -8940 32;-13135 -24391 50;-13058 16186 32;-12722 16186 32;-12722 21066 32;-13058 21066 32;-13058 16186 50;-13064 29485 32;-12693 29485 32;-12693 30722 32;-13064 30722 32;-13064 29485 50;-13247 97034 32;-12628 97034 32;-12628 100163 32;-13247 100163 32;-13247 97034 50;-13097 58412 32;-12734 58412 32;-12734 61512 32;-13097 61512 32;-13097 58412 50;24437 65027 32;24755 65027 32;24755 69959 32;24437 69959 32;24437 65027 50;62093 -43270;62093 -44202;24593 -63582;24593 -64514;-12907 -69552;-12907 -70484;-50415 -56514;-50415 -57446;-87907 75943;-87907 75011;-61777 6671;-59865 -675 1;-59704 -1366;-59397 -1821;-58748 -2106 1;-58038 -2418;-57546 -2345;-56847 -2682 1;-56552 -2824;-56556 -3104;-56410 -3397 1;-56291 -3636;-56214 -4093;-56480 -4077 1;-56850 -4055;-57052 -3981;-57405 -3868 1;-57746 -3759;-58103 -4103;-58103 -4461 1;-58103 -5022;-57921 -5446;-57440 -5735 1;-56833 -6099;-57117 -6738;-57143 -7445 1;-57171 -8196;-57248 -8784;-57090 -9364;-54760 -17861 1;-54461 -18952;-53410 -19207;-52278 -19382 1;-50704 -19636;-49098 -18950;-47816 -17606 1;-46157 -15867;-46149 -13999;-46467 -11617 1;-46602 -10606;-47251 -9928;-48260 -9778 1;-49255 -9630;-49794 -9485;-50215 -10431 1;-50528 -11135;-49568 -11505;-49620 -12349 1;-49697 -13596;-52184 -13647;-52081 -11757 1;-52027 -10780;-52107 -10172;-51505 -9401 1;-50918 -8650;-50295 -8533;-49359 -8355 1;-48108 -8118;-47247 -8285;-46149 -8931 1;-44572 -9859;-44469 -11385;-44208 -13196 1;-43662 -16985;-46000 -19475;-49266 -21471 1;-50314 -22111;-50798 -22096;-51830 -22761 1;-52384 -23118;-52428 -23955;-52332 -24607 1;-51945 -27234;-51696 -28526;-51066 -31105 1;-50488 -33471;-50377 -34918;-49862 -37298;-49324 -39793 16;-48266 -43193;-44969 -55600 1;-44770 -56350;-44658 -56771;-44459 -57521 1;-44403 -57731;-44126 -57609;-43909 -57599 1;-37936 -57328;-34589 -57125;-28611 -57007 1;-28172 -56999;-27797 -57000;-27550 -56637 1;-27347 -56339;-26998 -56491;-26637 -56489 1;-22731 -56463;-20534 -56558;-16644 -56908 1;-14125 -57135;-12753 -57589;-10241 -57885 1;-8135 -58133;-6949 -58248;-4832 -58374 1;-3352 -58462;-2528 -58619;-1046 -58670 1;-695 -58682;-321 -58841;-313 -59193 1;-299 -59779;-292 -60108;-279 -60694 1;-271 -61060;-683 -61180;-1045 -61235 1;-4468 -61755;-6395 -62109;-9856 -62230 1;-13334 -62352;-15274 -62620;-18737 -62963 1;-24631 -63547;-27958 -63634;-33847 -64260 1;-36788 -64573;-38425 -64883;-41324 -65469 1;-41971 -65600;-42155 -65883;-42027 -66530;-41134 -71044 16;-90081 87295 1;-88904 87663;-88866 87631;-87777 87896 1;-86608 88180;-85808 87191;-85477 86452;-74252 52606 1;-74077 52075;-73143 51784;-72928 51898 1;-72514 52117;-72271 52360;-72088 52657 1;-69677 56571;-68581 58935;-65929 62690 1;-65359 63497;-65039 63950;-64469 64757 16;-58129 64311 1;-58237 63013;-58757 62349;-59461 61252 1;-61129 58653;-62367 57397;-63977 54762 1;-65401 52432;-66406 51244;-67653 48815 1;-68965 46259;-69382 44645;-69627 41783 1;-70167 35481;-69198 33882;-68259 30659;-63792 15201;-63391 13475 1;-63213 12954;-62713 12716;-62177 12846 1;-60743 13194;-59861 13450;-58374 13423 1;-57251 13403;-56529 13169;-55670 12446 1;-55374 12197;-55327 11948;-55112 11626 1;-54774 11119;-54387 10945;-54187 10369 1;-53834 9353;-53814 8732;-53577 7683 1;-53363 6737;-53908 5958;-54763 5502 1;-55535 5090;-56383 5488;-56892 6200 1;-57257 6711;-57329 7272;-56996 7805 1;-56763 8177;-56738 8505;-56874 8922 1;-57021 9373;-57429 9567;-57904 9567 1;-58992 9567;-59431 8764;-60468 8433 1;-61332 8157;-61963 7532;-61777 6671 16;23449 -54909 1;24004 -55081;24327 -55630;24170 -56134 1;24013 -56638;23436 -56907;22881 -56735 1;22326 -56562;22003 -56013;22160 -55509 1;22316 -55005;22893 -54736;23449 -54909 18;-98032 -141948;Orienteering map24405 -141380;Scale:24405 -136077;Contours:59183 -136073;2.5 m59183 -130917;May 201359183 -123479;Thomas Schöps24405 -123483;Cartography:59183 -141376;1 : 4,00024405 -130921;Standing:-100736 -132215;Garching-100438 -131472;Garching-99743 -107017;Special Signatures-99428 -85496;Legend-96266 109471;Orienteering in ...-96409 113730;Munich:73320 -54693;N69062 -61008;77555 -61008;73312 -68970;69062 -61008 18;85399 110654;N81141 104339;89634 104339;85391 96377;81141 104339 18;-85692 22052;N-89950 15737;-81457 15737;-85700 7775;-89950 15737 18; +-94509 -76769 32;-91828 -76769 32;-91828 -74145 32;-94509 -74145 32;-94509 -76769 50;-94217 -80160 32;-92083 -80160 32;-92083 -78042 32;-94217 -78042 32;-94217 -80160 50;-94509 -62288 32;-91828 -62288 32;-91828 -59664 32;-94509 -59664 32;-94509 -62288 50;-94509 -65897 32;-91828 -65897 32;-91828 -63273 32;-94509 -63273 32;-94509 -65897 50;-93630 -69541;-91828 -69541 32;-91828 -66917 32;-93630 -66917 16;-94509 -33067 32;-91828 -33067 32;-91828 -30443 32;-94509 -30443 32;-94509 -33067 50;-94509 -18612 32;-91828 -18612 32;-91828 -15988 32;-94509 -15988 32;-94509 -18612 50;-94509 -22221 32;-91828 -22221 32;-91828 -19597 32;-94509 -19597 32;-94509 -22221 50;-97187 -69541 32;-95398 -69541 32;-95398 -66917 32;-97187 -66917 32;-97187 -69541 50;-97187 -18612 32;-94506 -18612 32;-94506 -15988 32;-97187 -15988 32;-97187 -18612 50;-96905 -80131 32;-94837 -80131 32;-94837 -78071 32;-96905 -78071 32;-96905 -80131 50;-97187 -33067 32;-94506 -33067 32;-94506 -30443 32;-97187 -30443 32;-97187 -33067 50;-97187 -65897 32;-94506 -65897 32;-94506 -63273 32;-97187 -63273 32;-97187 -65897 50;-97187 -22221 32;-94506 -22221 32;-94506 -19597 32;-97187 -19597 32;-97187 -22221 50;-97187 -76769 32;-94506 -76769 32;-94506 -74145 32;-97187 -74145 32;-97187 -76769 50;-97187 -62288 32;-94506 -62288 32;-94506 -59664 32;-97187 -59664 32;-97187 -62288 50;-95397 -69541 32;-93622 -69541 32;-93622 -66917 32;-95397 -66917 32;-95397 -69541 50;-97186 -70537 32;-97186 -73161 32;-91827 -73161 32;-91827 -70537 32;-97186 -70537 50;-95825 -57271;-93188 -57246;-96926 -52501 1;-96327 -53305;-95862 -53873;-95644 -54852;-95060 -52368 1;-94445 -53213;-94272 -53817;-94000 -54826;-92735 -52616;-92735 -54560;-92735 -52616;-92735 -54560;-97176 -50002;-91837 -50002;-97176 -46314;-91837 -46314;-97176 -42701;-91837 -42701;-97176 -39024;-91837 -39024;-97176 -35418;-91837 -35418;-96856 -27135;-95292 -29044;-95238 -27135;-93674 -29044;-93744 -27135;-92180 -29044;-97015 -24865 1;-96587 -25062;-96095 -25420;-95626 -25727;-97003 -23702 1;-95974 -23917;-95416 -24580;-94390 -24352;-95703 -24177;-93450 -24790 1;-93191 -25215;-92761 -25425;-92488 -25260 1;-92215 -25094;-92204 -24615;-92462 -24190 1;-92721 -23764;-93151 -23554;-93424 -23720 1;-93697 -23885;-93708 -24364;-93450 -24790 18;-97012 -24218 1;-96005 -24698;-95019 -25545;-94318 -25362;-96651 -12597;-95063 -14610;-93963 -12572;-92375 -14585;-95844 -9873;-94070 -8966;-92558 -11017;-95847 -6305;-93964 -5333;-92452 -7384;-97183 -97983 32;-94502 -97983 32;-94502 -95359 32;-97183 -95359 32;-97183 -97983 50;-94505 -97983 32;-91824 -97983 32;-91824 -95359 32;-94505 -95359 32;-94505 -97983 50;-97183 -101608 32;-94502 -101608 32;-94502 -98984 32;-97183 -98984 32;-97183 -101608 50;-94505 -101608 32;-91824 -101608 32;-91824 -98984 32;-94505 -98984 32;-94505 -101608 50;-91824 -101608;-97183 -101608;-97183 -98984;-91824 -98984;-91824 -101608 18;-94724 99498;29307 113498;38500 125237;45571 125803;49531 117317;74846 105013;77816 98932;91676 -31463;87716 -42777;78947 -41363;77816 -34857;72159 -34857;66302 -44060;56502 -43843;52359 -67385;26620 -63708;-47487 -75871;-48878 -61311;-52432 -52082;-86725 72900;-89598 78252;-95147 91437;-94724 99498 18;-87750 85332;-87944 85220;-88019 84989;-88000 84582;-87663 84664;-87700 85032;-87750 85332 18;-51203 55455 32;-49647 55455 32;-49647 60864 32;-51203 60864 32;-51203 55455 50;-50724 14979 32;-50024 14979 32;-50024 15742 32;-50724 15742 32;-50724 14979 50;-50688 1358 32;-50051 1358 32;-50051 -442 32;-50688 -442 32;-50688 1358 50;-13135 -24391 32;-12709 -24391 32;-12709 -8940 32;-13135 -8940 32;-13135 -24391 50;-13058 16186 32;-12722 16186 32;-12722 21066 32;-13058 21066 32;-13058 16186 50;-13064 29485 32;-12693 29485 32;-12693 30722 32;-13064 30722 32;-13064 29485 50;-13247 97034 32;-12628 97034 32;-12628 100163 32;-13247 100163 32;-13247 97034 50;-13097 58412 32;-12734 58412 32;-12734 61512 32;-13097 61512 32;-13097 58412 50;24437 65027 32;24755 65027 32;24755 69959 32;24437 69959 32;24437 65027 50;62093 -43270;62093 -44202;24593 -63582;24593 -64514;-12907 -69552;-12907 -70484;-50415 -56514;-50415 -57446;-87907 75943;-87907 75011;-61777 6671;-59865 -675 1;-59704 -1366;-59397 -1821;-58748 -2106 1;-58038 -2418;-57546 -2345;-56847 -2682 1;-56552 -2824;-56556 -3104;-56410 -3397 1;-56291 -3636;-56214 -4093;-56480 -4077 1;-56850 -4055;-57052 -3981;-57405 -3868 1;-57746 -3759;-58103 -4103;-58103 -4461 1;-58103 -5022;-57921 -5446;-57440 -5735 1;-56833 -6099;-57117 -6738;-57143 -7445 1;-57171 -8196;-57248 -8784;-57090 -9364;-54760 -17861 1;-54461 -18952;-53410 -19207;-52278 -19382 1;-50704 -19636;-49098 -18950;-47816 -17606 1;-46157 -15867;-46149 -13999;-46467 -11617 1;-46602 -10606;-47251 -9928;-48260 -9778 1;-49255 -9630;-49794 -9485;-50215 -10431 1;-50528 -11135;-49568 -11505;-49620 -12349 1;-49697 -13596;-52184 -13647;-52081 -11757 1;-52027 -10780;-52107 -10172;-51505 -9401 1;-50918 -8650;-50295 -8533;-49359 -8355 1;-48108 -8118;-47247 -8285;-46149 -8931 1;-44572 -9859;-44469 -11385;-44208 -13196 1;-43662 -16985;-46000 -19475;-49266 -21471 1;-50314 -22111;-50798 -22096;-51830 -22761 1;-52384 -23118;-52428 -23955;-52332 -24607 1;-51945 -27234;-51696 -28526;-51066 -31105 1;-50488 -33471;-50377 -34918;-49862 -37298;-49324 -39793 16;-48266 -43193;-44969 -55600 1;-44770 -56350;-44658 -56771;-44459 -57521 1;-44403 -57731;-44126 -57609;-43909 -57599 1;-37936 -57328;-34589 -57125;-28611 -57007 1;-28172 -56999;-27797 -57000;-27550 -56637 1;-27347 -56339;-26998 -56491;-26637 -56489 1;-22731 -56463;-20534 -56558;-16644 -56908 1;-14125 -57135;-12753 -57589;-10241 -57885 1;-8135 -58133;-6949 -58248;-4832 -58374 1;-3352 -58462;-2528 -58619;-1046 -58670 1;-695 -58682;-321 -58841;-313 -59193 1;-299 -59779;-292 -60108;-279 -60694 1;-271 -61060;-683 -61180;-1045 -61235 1;-4468 -61755;-6395 -62109;-9856 -62230 1;-13334 -62352;-15274 -62620;-18737 -62963 1;-24631 -63547;-27958 -63634;-33847 -64260 1;-36788 -64573;-38425 -64883;-41324 -65469 1;-41971 -65600;-42155 -65883;-42027 -66530;-41134 -71044 16;-90081 87295 1;-88904 87663;-88866 87631;-87777 87896 1;-86608 88180;-85808 87191;-85477 86452;-74252 52606 1;-74077 52075;-73143 51784;-72928 51898 1;-72514 52117;-72271 52360;-72088 52657 1;-69677 56571;-68581 58935;-65929 62690 1;-65359 63497;-65039 63950;-64469 64757 16;-58129 64311 1;-58237 63013;-58757 62349;-59461 61252 1;-61129 58653;-62367 57397;-63977 54762 1;-65401 52432;-66406 51244;-67653 48815 1;-68965 46259;-69382 44645;-69627 41783 1;-70167 35481;-69198 33882;-68259 30659;-63792 15201;-63391 13475 1;-63213 12954;-62713 12716;-62177 12846 1;-60743 13194;-59861 13450;-58374 13423 1;-57251 13403;-56529 13169;-55670 12446 1;-55374 12197;-55327 11948;-55112 11626 1;-54774 11119;-54387 10945;-54187 10369 1;-53834 9353;-53814 8732;-53577 7683 1;-53363 6737;-53908 5958;-54763 5502 1;-55535 5090;-56383 5488;-56892 6200 1;-57257 6711;-57329 7272;-56996 7805 1;-56763 8177;-56738 8505;-56874 8922 1;-57021 9373;-57429 9567;-57904 9567 1;-58992 9567;-59431 8764;-60468 8433 1;-61332 8157;-61963 7532;-61777 6671 16;23449 -54909 1;24004 -55081;24327 -55630;24170 -56134 1;24013 -56638;23436 -56907;22881 -56735 1;22326 -56562;22003 -56013;22160 -55509 1;22316 -55005;22893 -54736;23449 -54909 18;-98032 -141948;Orienteering map24405 -141380;Scale:24405 -136077;Contours:59183 -136073;2.5 m59183 -130917;May 201359183 -123479;Thomas Schöps24405 -123483;Cartography:59183 -141376;1 : 4,00024405 -130921;Standing:-100736 -132215;Garching-100438 -131472;Garching-99743 -107017;Special Signatures-99428 -85496;Legend-96266 109471;Orienteering in ...-96409 113730;Munich:73320 -54693;N69062 -61008;77555 -61008;73312 -68970;69062 -61008 18;85399 110654;N81141 104339;89634 104339;85391 96377;81141 104339 18;-85692 22052;N-89950 15737;-81457 15737;-85700 7775;-89950 15737 18; diff --git a/examples/forest sample.omap b/examples/forest sample.omap index 3c0ae1fb0..f8a698abc 100644 --- a/examples/forest sample.omap +++ b/examples/forest sample.omap @@ -7,6 +7,6 @@ given without the dot.A solid line indicates that the boundary is marked continuously (tapes, etc.) on the ground.A dashed line indicates intermittent marking on the ground.An area presenting danger to the competitor is shown with cross-hatched diagonal lines.A route which is out-of-bounds is shown with crosses.1061 -1061;-1061 1061;1061 1061;-1061 -1061;The location of a first aid post.-1500 0;1500 0;0 -1500;0 1500;The location of a refreshment point which is not at a control.-1340 -1395;-820 1380;1340 -1395;820 1380;0 -1770 1;600 -1770;1200 -1620;1340 -1395 1;1200 -1170;600 -1020;0 -1020 1;-600 -1020;-1200 -1170;-1340 -1395 1;-1200 -1620;-600 -1770;0 -1770;-820 1380 1;-680 1680;680 1680;820 1380;This symbol provides a simple and quick way to make training courses. +- no line indicates no marking on the ground.A solid line indicates that the boundary is marked continuously (tapes, etc.) on the ground.A dashed line indicates intermittent marking on the ground.An area presenting danger to the competitor is shown with cross-hatched diagonal lines.A route which is out-of-bounds is shown with crosses.1061 -1061;-1061 1061;1061 1061;-1061 -1061;The location of a first aid post.-1500 0;1500 0;0 -1500;0 1500;The location of a refreshment point which is not at a control.-1340 -1395;-820 1380;1340 -1395;820 1380;0 -1770 1;600 -1770;1200 -1620;1340 -1395 1;1200 -1170;600 -1020;0 -1020 1;-600 -1020;-1200 -1170;-1340 -1395 1;-1200 -1620;-600 -1770;0 -1770;-820 1380 1;-680 1680;680 1680;820 1380;This symbol provides a simple and quick way to make training courses. -The purple line will extend a bit into the finish symbol. This is a shortcoming of this simple approach.3041 0;3541 0;-3021 3500;3041 0;-3021 -3500;-3021 3500 18;-600 0;600 0;0 0;The OpenOrienteering Logo.-12797 -557 1;-12755 -447;-12770 -420;-12873 -420 1;-12953 -420;-12973 -440;-12973 -520 1;-12973 -635;-12838 -663;-12797 -557 18;-933 2063 1;-933 1925;-920 1900;-851 1900 1;-780 1900;-770 1921;-781 2050 1;-789 2154;-814 2203;-863 2213 1;-920 2224;-933 2197;-933 2063;-933 2063 18;-8875 -3860 1;-8922 -3920;-8984 -3968;-9061 -4006 1;-9134 -4045;-9225 -4065;-9337 -4065 1;-9444 -4065;-9535 -4045;-9612 -4006 1;-9688 -3974;-9752 -3927;-9803 -3867 1;-9855 -3807;-9895 -3737;-9925 -3655 1;-9950 -3578;-9970 -3500;-9982 -3418;-8723 -3418 1;-8725 -3500;-8740 -3578;-8768 -3655 1;-8789 -3732;-8824 -3800;-8875 -3860 18;-4230 -3923 1;-4183 -3737;-4160 -3527;-4160 -3296;-4160 -1395;-5113 -1395;-5113 -3182 1;-5113 -3488;-5155 -3707;-5235 -3833 1;-5317 -3961;-5468 -4027;-5690 -4027 1;-5759 -4027;-5830 -4021;-5907 -4013 1;-5983 -4008;-6052 -4004;-6112 -3993;-6112 -1395;-7064 -1395;-7064 -4646 1;-6903 -4693;-6694 -4736;-6438 -4774 1;-6181 -4818;-5913 -4838;-5631 -4838 1;-5347 -4838;-5110 -4800;-4921 -4723 1;-4730 -4652;-4579 -4547;-4467 -4410 1;-4357 -4273;-4277 -4111;-4230 -3923 18;-13524 1118 1;-13605 1126;-13667 1137;-13708 1150;-13708 3722;-14662 3722;-14662 536 1;-14492 476;-14292 420;-14060 369 1;-13827 314;-13565 286;-13280 286 1;-13229 286;-13167 290;-13096 299 1;-13022 303;-12951 312;-12878 325 1;-12806 333;-12733 345;-12660 363 1;-12587 375;-12526 392;-12474 414;-12634 1201 1;-12719 1180;-12819 1158;-12936 1137 1;-13051 1112;-13174 1098;-13306 1098 1;-13366 1098;-13439 1105;-13524 1118 18;-11093 -200 1;-11204 -101;-11336 -52;-11490 -52 1;-11642 -52;-11777 -101;-11893 -200 1;-12004 -303;-12059 -441;-12059 -616 1;-12059 -791;-12004 -927;-11893 -1026 1;-11777 -1128;-11642 -1179;-11490 -1179 1;-11336 -1179;-11204 -1128;-11093 -1026 1;-10978 -927;-10920 -791;-10920 -616 1;-10920 -441;-10978 -303;-11093 -200 18;-11009 3722;-11963 3722;-11963 357;-11009 357;-11009 3722 18;-8649 1053 1;-8755 1053;-8847 1073;-8924 1112 1;-9001 1145;-9065 1192;-9115 1252 1;-9167 1312;-9207 1381;-9237 1464 1;-9264 1539;-9282 1618;-9296 1700;-8034 1700 1;-8039 1618;-8054 1539;-8079 1464 1;-8101 1387;-8137 1318;-8189 1259 1;-8236 1199;-8297 1150;-8374 1112 1;-8445 1073;-8537 1053;-8649 1053 18;-5220 1105 1;-5297 1110;-5365 1115;-5425 1125;-5425 3722;-6378 3722;-6378 472 1;-6217 425;-6007 382;-5751 344 1;-5495 301;-5227 280;-4945 280 1;-4658 280;-4422 318;-4235 395 1;-4042 467;-3890 572;-3781 709 1;-3669 845;-3591 1007;-3544 1195 1;-3497 1381;-3474 1592;-3474 1821;-3474 3722;-4427 3722;-4427 1937 1;-4427 1630;-4467 1411;-4549 1285 1;-4628 1156;-4780 1092;-5002 1092 1;-5070 1092;-5143 1097;-5220 1105 18;-2636 2346;-2636 -481;-1683 -634;-1683 357;-539 357;-539 1150;-1683 1150;-1683 2333 1;-1683 2535;-1648 2694;-1581 2813 1;-1508 2933;-1365 2993;-1151 2993 1;-1050 2993;-945 2984;-838 2966 1;-728 2946;-627 2918;-539 2884;-404 3626 1;-518 3673;-646 3712;-787 3748 1;-928 3780;-1102 3799;-1305 3799 1;-1566 3799;-1781 3764;-1951 3696 1;-2123 3624;-2259 3526;-2361 3402 1;-2463 3274;-2536 3121;-2579 2941 1;-2618 2763;-2636 2565;-2636 2346 18;2142 1464 1;2121 1387;2084 1318;2032 1259 1;1986 1199;1924 1150;1847 1112 1;1776 1073;1685 1053;1572 1053 1;1466 1053;1375 1073;1298 1112 1;1221 1145;1156 1192;1106 1252 1;1054 1312;1014 1381;984 1464 1;958 1539;939 1618;926 1700;2187 1700 1;2183 1618;2168 1539;2142 1464 18;5923 1700 1;5919 1618;5904 1539;5878 1464 1;5856 1387;5821 1318;5769 1259 1;5723 1199;5661 1150;5585 1112 1;5511 1073;5419 1053;5308 1053 1;5201 1053;5110 1073;5033 1112 1;4957 1145;4893 1192;4841 1252 1;4790 1312;4750 1381;4720 1464 1;4695 1539;4675 1618;4663 1700;5923 1700 18;8718 1118 1;8637 1126;8575 1137;8534 1150;8534 3722;7581 3722;7581 536 1;7750 476;7950 420;8182 369 1;8415 314;8677 286;8962 286 1;9013 286;9075 290;9146 299 1;9220 303;9292 312;9365 325 1;9437 333;9510 345;9583 363 1;9655 375;9717 392;9768 414;9608 1201 1;9523 1180;9424 1158;9306 1137 1;9191 1112;9069 1098;8937 1098 1;8877 1098;8804 1105;8718 1118 18;10350 -200 1;10238 -303;10183 -441;10183 -616 1;10183 -791;10238 -927;10350 -1026 1;10465 -1128;10600 -1179;10752 -1179 1;10906 -1179;11038 -1128;11149 -1026 1;11264 -927;11323 -791;11323 -616 1;11323 -441;11264 -303;11149 -200 1;11038 -101;10906 -52;10752 -52 1;10600 -52;10465 -101;10350 -200 18;11233 3722;10279 3722;10279 357;11233 357;11233 3722 18;14726 709 1;14836 845;14916 1007;14963 1195 1;15010 1381;15033 1592;15033 1821;15033 3722;14080 3722;14080 1937 1;14080 1630;14039 1411;13958 1285 1;13876 1156;13725 1092;13504 1092 1;13435 1092;13363 1097;13287 1105 1;13210 1110;13142 1115;13082 1125;13082 3722;12129 3722;12129 472 1;12290 425;12499 382;12756 344 1;13012 301;13280 280;13562 280 1;13847 280;14083 318;14272 395 1;14463 467;14614 572;14726 709 18;-17051 -1307 1;-17299 -1307;-17525 -1349;-17729 -1434 1;-17931 -1521;-18102 -1639;-18247 -1794 1;-18392 -1951;-18505 -2139;-18587 -2355 1;-18669 -2579;-18708 -2820;-18708 -3085 1;-18708 -3350;-18669 -3591;-18587 -3808 1;-18502 -4027;-18387 -4211;-18242 -4365 1;-18092 -4518;-17917 -4638;-17717 -4723 1;-17512 -4808;-17291 -4851;-17051 -4851 1;-16808 -4851;-16586 -4808;-16386 -4723 1;-16182 -4638;-16006 -4518;-15861 -4365 1;-15716 -4211;-15603 -4027;-15523 -3808 1;-15442 -3591;-15401 -3350;-15401 -3085 1;-15401 -2820;-15440 -2579;-15517 -2355 1;-15593 -2139;-15703 -1951;-15848 -1794 1;-15993 -1639;-16168 -1521;-16373 -1434 1;-16574 -1349;-16800 -1307;-17051 -1307 18;-17051 -2126 1;-16834 -2126;-16668 -2210;-16552 -2383 1;-16433 -2557;-16373 -2792;-16373 -3085 1;-16373 -3380;-16433 -3610;-16552 -3777 1;-16668 -3946;-16834 -4034;-17051 -4034 1;-17269 -4034;-17437 -3946;-17557 -3777 1;-17675 -3610;-17736 -3380;-17736 -3085 1;-17736 -2792;-17675 -2557;-17557 -2383 1;-17437 -2210;-17269 -2126;-17051 -2126 18;-14662 -213;-14662 -4646 1;-14576 -4673;-14478 -4697;-14369 -4716 1;-14257 -4743;-14142 -4765;-14022 -4781 1;-13898 -4798;-13776 -4811;-13652 -4819 1;-13524 -4833;-13402 -4838;-13287 -4838 1;-13009 -4838;-12763 -4796;-12544 -4711 1;-12328 -4630;-12144 -4513;-11995 -4358 1;-11846 -4210;-11732 -4027;-11657 -3808 1;-11574 -3591;-11535 -3348;-11535 -3078 1;-11535 -2819;-11566 -2582;-11629 -2368 1;-11694 -2156;-11788 -1972;-11911 -1819 1;-12034 -1666;-12189 -1546;-12373 -1461 1;-12556 -1376;-12765 -1333;-13006 -1333 1;-13137 -1333;-13261 -1346;-13377 -1371 1;-13492 -1395;-13602 -1432;-13708 -1479;-13708 -213;-14662 -213 18;-13184 -2139 1;-12733 -2139;-12506 -2443;-12506 -3054 1;-12506 -3348;-12572 -3582;-12704 -3756 1;-12837 -3936;-13032 -4027;-13293 -4027 1;-13379 -4027;-13457 -4021;-13530 -4013 1;-13602 -4008;-13662 -4004;-13708 -3993;-13708 -2274 1;-13648 -2234;-13572 -2202;-13479 -2177 1;-13381 -2152;-13282 -2139;-13184 -2139 18;-9182 -1307 1;-9485 -1307;-9750 -1352;-9976 -1440 1;-10198 -1530;-10383 -1652;-10533 -1806 1;-10678 -1964;-10787 -2149;-10858 -2362 1;-10926 -2575;-10962 -2807;-10962 -3054 1;-10962 -3352;-10917 -3612;-10827 -3833 1;-10733 -4060;-10611 -4248;-10462 -4396 1;-10314 -4547;-10141 -4660;-9950 -4736 1;-9754 -4813;-9553 -4851;-9349 -4851 1;-8872 -4851;-8494 -4705;-8217 -4410 1;-7939 -4120;-7801 -3692;-7801 -3123 1;-7801 -3069;-7803 -3007;-7808 -2939 1;-7810 -2873;-7816 -2817;-7819 -2766;-9982 -2766 1;-9961 -2569;-9870 -2413;-9707 -2299 1;-9545 -2184;-9327 -2126;-9055 -2126 1;-8881 -2126;-8708 -2141;-8542 -2171 1;-8372 -2205;-8234 -2246;-8127 -2292;-7999 -1517 1;-8051 -1493;-8119 -1468;-8204 -1440 1;-8289 -1416;-8385 -1395;-8492 -1378 1;-8594 -1356;-8706 -1339;-8824 -1326 1;-8944 -1314;-9063 -1307;-9182 -1307 18;-9982 -3418;-8723 -3418 1;-8725 -3500;-8740 -3578;-8768 -3655 1;-8789 -3732;-8824 -3800;-8875 -3860 1;-8922 -3920;-8984 -3968;-9061 -4006 1;-9134 -4045;-9225 -4065;-9337 -4065 1;-9444 -4065;-9535 -4045;-9612 -4006 1;-9688 -3974;-9752 -3927;-9803 -3867 1;-9855 -3807;-9895 -3737;-9925 -3655 1;-9950 -3578;-9970 -3500;-9982 -3418 18;-17051 -2126 1;-17269 -2126;-17437 -2210;-17557 -2383 1;-17675 -2557;-17736 -2792;-17736 -3085 1;-17736 -3380;-17675 -3610;-17557 -3777 1;-17437 -3946;-17269 -4034;-17051 -4034 1;-16834 -4034;-16668 -3946;-16552 -3777 1;-16433 -3610;-16373 -3380;-16373 -3085 1;-16373 -2792;-16433 -2557;-16552 -2383 1;-16668 -2210;-16834 -2126;-17051 -2126 18;-17064 -2593 1;-16944 -2591;-16842 -2808;-16838 -3077 1;-16834 -3347;-16928 -3567;-17049 -3569 1;-17170 -3571;-17271 -3354;-17275 -3084 1;-17280 -2815;-17185 -2595;-17064 -2593 18;-8496 3810 1;-8798 3810;-9062 3765;-9288 3677 1;-9510 3588;-9696 3466;-9845 3312 1;-9990 3154;-10098 2969;-10171 2756 1;-10240 2542;-10273 2311;-10273 2065 1;-10273 1766;-10230 1507;-10140 1285 1;-10045 1058;-9923 870;-9775 722 1;-9625 572;-9455 459;-9264 382 1;-9067 305;-8867 267;-8662 267 1;-8184 267;-7806 414;-7529 709 1;-7252 998;-7113 1426;-7113 1995 1;-7113 2050;-7116 2112;-7119 2180 1;-7124 2245;-7128 2301;-7132 2353;-9296 2353 1;-9273 2550;-9182 2704;-9020 2820 1;-8857 2934;-8640 2993;-8368 2993 1;-8193 2993;-8022 2978;-7855 2948 1;-7684 2912;-7546 2873;-7440 2826;-7311 3601 1;-7363 3626;-7431 3651;-7516 3677 1;-7603 3703;-7697 3724;-7804 3741 1;-7908 3763;-8017 3779;-8137 3793 1;-8257 3804;-8376 3810;-8496 3810 18;-9296 1700;-8034 1700 1;-8039 1618;-8054 1539;-8079 1464 1;-8101 1387;-8137 1318;-8189 1259 1;-8236 1199;-8297 1150;-8374 1112 1;-8445 1073;-8537 1053;-8649 1053 1;-8755 1053;-8847 1073;-8924 1112 1;-9001 1145;-9065 1192;-9115 1252 1;-9167 1312;-9207 1381;-9237 1464 1;-9264 1539;-9282 1618;-9296 1700 18;1726 3810 1;1422 3810;1159 3765;933 3677 1;712 3588;524 3466;376 3312 1;231 3154;123 2969;49 2756 1;-19 2542;-52 2311;-52 2065 1;-52 1766;-9 1507;81 1285 1;177 1058;298 870;446 722 1;596 572;766 459;958 382 1;1154 305;1354 267;1559 267 1;2038 267;2416 414;2692 709 1;2968 998;3109 1426;3109 1995 1;3109 2050;3105 2112;3102 2180 1;3097 2245;3094 2301;3088 2353;926 2353 1;947 2550;1039 2704;1201 2820 1;1364 2934;1581 2993;1854 2993 1;2029 2993;2199 2978;2365 2948 1;2538 2912;2675 2873;2782 2826;2910 3601 1;2859 3626;2790 3651;2705 3677 1;2619 3703;2524 3724;2417 3741 1;2314 3763;2204 3779;2084 3793 1;1965 3804;1846 3810;1726 3810 18;926 1700;2187 1700 1;2183 1618;2168 1539;2142 1464 1;2121 1387;2084 1318;2032 1259 1;1986 1199;1924 1150;1847 1112 1;1776 1073;1685 1053;1572 1053 1;1466 1053;1375 1073;1298 1112 1;1221 1145;1156 1192;1106 1252 1;1054 1312;1014 1381;984 1464 1;958 1539;939 1618;926 1700 18;5463 3810 1;5160 3810;4895 3765;4668 3677 1;4446 3588;4262 3466;4112 3312 1;3967 3154;3858 2969;3787 2756 1;3719 2542;3684 2311;3684 2065 1;3684 1766;3729 1507;3819 1285 1;3911 1058;4033 870;4183 722 1;4332 572;4503 459;4695 382 1;4891 305;5091 267;5297 267 1;5773 267;6151 414;6428 709 1;6706 998;6844 1426;6844 1995 1;6844 2050;6843 2112;6837 2180 1;6834 2245;6829 2301;6826 2353;4663 2353 1;4683 2550;4775 2704;4938 2820 1;5100 2934;5318 2993;5590 2993 1;5765 2993;5936 2978;6103 2948 1;6272 2912;6411 2873;6518 2826;6646 3601 1;6594 3626;6526 3651;6441 3677 1;6356 3703;6259 3724;6152 3741 1;6051 3763;5939 3779;5821 3793 1;5701 3804;5581 3810;5463 3810 18;4663 1700;5923 1700 1;5919 1618;5904 1539;5878 1464 1;5856 1387;5821 1318;5769 1259 1;5723 1199;5661 1150;5585 1112 1;5511 1073;5419 1053;5308 1053 1;5201 1053;5110 1073;5033 1112 1;4957 1145;4893 1192;4841 1252 1;4790 1312;4750 1381;4720 1464 1;4695 1539;4675 1618;4663 1700 18;17092 4924 1;16887 4924;16682 4905;16477 4867 1;16272 4832;16083 4785;15908 4725;16074 3926 1;16224 3986;16379 4032;16543 4067 1;16707 4101;16896 4119;17105 4119 1;17377 4119;17570 4059;17680 3939 1;17796 3819;17854 3666;17854 3479;17854 3357 1;17750 3404;17644 3441;17533 3466 1;17427 3487;17309 3498;17182 3498 1;16717 3498;16361 3361;16113 3087 1;15866 2811;15743 2424;15743 1930 1;15743 1683;15781 1458;15857 1259 1;15934 1053;16044 878;16189 733 1;16339 589;16521 478;16734 402 1;16947 320;17187 280;17457 280 1;17572 280;17689 286;17809 299 1;17931 307;18053 320;18173 337 1;18292 354;18405 375;18512 402 1;18624 422;18722 446;18806 472;18806 3299 1;18806 3849;18665 4257;18385 4522 1;18107 4790;17677 4924;17092 4924 18;17360 2730 1;17459 2730;17550 2718;17636 2691 1;17720 2666;17794 2636;17854 2603;17854 1080 1;17807 1072;17750 1065;17687 1060 1;17623 1052;17548 1047;17464 1047 1;17212 1047;17024 1130;16900 1297 1;16776 1464;16714 1675;16714 1930 1;16714 2463;16930 2730;17360 2730 18;-17051 2993 1;-17269 2993;-17437 2908;-17557 2736 1;-17675 2561;-17736 2326;-17736 2033 1;-17736 1738;-17675 1509;-17557 1342 1;-17437 1171;-17269 1085;-17051 1085 1;-16834 1085;-16668 1171;-16552 1342 1;-16433 1509;-16373 1738;-16373 2033 1;-16373 2326;-16433 2561;-16552 2736 1;-16668 2908;-16834 2993;-17051 2993 18;-17064 2526 1;-16944 2528;-16842 2311;-16838 2042 1;-16834 1772;-16928 1552;-17049 1550 1;-17170 1548;-17271 1765;-17275 2035 1;-17280 2304;-17185 2524;-17064 2526 18;-17051 3810 1;-17299 3810;-17525 3769;-17729 3684 1;-17931 3598;-18102 3479;-18247 3324 1;-18392 3168;-18505 2980;-18587 2763 1;-18669 2540;-18708 2298;-18708 2033 1;-18708 1768;-18669 1526;-18587 1310 1;-18502 1092;-18387 906;-18242 754 1;-18092 600;-17917 480;-17717 395 1;-17512 310;-17291 267;-17051 267 1;-16808 267;-16586 310;-16386 395 1;-16182 480;-16006 600;-15861 754 1;-15716 906;-15603 1092;-15523 1310 1;-15442 1526;-15401 1768;-15401 2033 1;-15401 2298;-15440 2540;-15517 2763 1;-15593 2980;-15703 3168;-15848 3324 1;-15993 3479;-16168 3598;-16373 3684 1;-16574 3769;-16800 3810;-17051 3810 18;-17051 2993 1;-16834 2993;-16668 2908;-16552 2736 1;-16433 2561;-16373 2326;-16373 2033 1;-16373 1738;-16433 1509;-16552 1342 1;-16668 1171;-16834 1085;-17051 1085 1;-17269 1085;-17437 1171;-17557 1342 1;-17675 1509;-17736 1738;-17736 2033 1;-17736 2326;-17675 2561;-17557 2736 1;-17437 2908;-17269 2993;-17051 2993 18;17090 5390 1;16864 5390;16623 5362;16391 5321 1;16389 5320;16389 5320;16387 5320 1;16169 5284;15963 5240;15758 5170 1;15555 5102;15409 4847;15450 4637 1;15450 4635;15450 4634;15450 4632;15538 4221 1;15549 4165;15526 4109;15478 4079 1;15431 4049;15369 4052;15324 4088 1;15245 4152;15138 4191;15033 4191;14080 4191 1;13930 4193;13775 4107;13692 3983 1;13669 3944;13625 3921;13580 3921 1;13534 3921;13492 3944;13466 3983 1;13385 4107;13233 4191;13083 4191;12131 4191 1;12001 4191;11866 4131;11781 4032 1;11755 4004;11719 3987;11680 3987 1;11642 3987;11606 4004;11581 4032 1;11496 4131;11364 4191;11234 4191;10281 4191 1;10048 4193;9815 3957;9815 3724;9815 1796 1;9815 1758;9798 1721;9770 1697 1;9741 1670;9703 1658;9665 1663 1;9608 1670;9553 1668;9498 1655 1;9433 1638;9341 1618;9227 1597 1;9221 1595;9217 1593;9210 1592 1;9161 1582;9142 1582;9157 1584 1;9118 1578;9078 1590;9048 1615 1;9018 1640;9001 1678;9001 1716 1;9001 1716;9001 3724;9001 3724 1;9001 3957;8768 4193;8535 4191;7582 4191 1;7424 4191;7262 4099;7183 3962 1;7162 3926;7125 3900;7082 3894 1;7040 3889;6999 3902;6969 3932 1;6935 3966;6899 3996;6855 4016 1;6768 4059;6679 4092;6574 4124 1;6467 4157;6364 4178;6253 4195 1;6244 4197;6236 4199;6226 4202 1;6107 4227;5991 4240;5870 4254 1;5738 4267;5601 4279;5461 4279 1;5121 4279;4808 4231;4520 4120 1;4514 4118;4506 4114;4498 4110 1;4220 3998;3977 3840;3778 3636 1;3717 3566;3663 3494;3609 3412 1;3571 3361;3503 3344;3445 3371 1;3389 3396;3357 3459;3370 3521 1;3404 3711;3293 3930;3120 4016 1;3034 4060;2945 4092;2837 4124 1;2732 4157;2628 4178;2517 4195 1;2508 4197;2499 4199;2490 4202 1;2372 4227;2256 4240;2134 4254 1;2001 4267;1866 4279;1726 4279 1;1386 4279;1071 4231;785 4120 1;778 4118;771 4114;761 4110 1;562 4029;383 3917;218 3782 1;186 3757;145 3748;105 3757 1;64 3765;32 3793;13 3829 1;-35 3929;-124 4013;-229 4054 1;-362 4109;-512 4164;-678 4204 1;-871 4251;-1073 4266;-1303 4266 1;-1606 4266;-1876 4227;-2127 4126 1;-2355 4031;-2561 3892;-2717 3706 1;-2719 3701;-2721 3699;-2719 3702 1;-2716 3707;-2718 3706;-2721 3700 1;-2724 3694;-2734 3667;-2764 3624 1;-2799 3577;-2859 3558;-2915 3576 1;-2969 3594;-3007 3646;-3006 3704;-3006 3724 1;-3006 3957;-3239 4193;-3473 4191;-4427 4191 1;-4577 4193;-4730 4107;-4814 3983 1;-4838 3944;-4880 3921;-4927 3921 1;-4972 3921;-5013 3944;-5038 3983 1;-5122 4107;-5274 4191;-5421 4191;-6377 4191 1;-6533 4191;-6696 4099;-6777 3962 1;-6796 3926;-6833 3900;-6875 3894 1;-6916 3889;-6958 3902;-6988 3932 1;-7021 3966;-7059 3996;-7101 4016 1;-7101 4017;-7104 4016;-7104 4016 1;-7191 4059;-7278 4092;-7384 4124 1;-7489 4157;-7592 4178;-7704 4195 1;-7714 4197;-7722 4199;-7729 4199 1;-7731 4201;-7733 4202;-7735 4204 1;-7849 4227;-7966 4240;-8088 4254 1;-8221 4267;-8355 4279;-8496 4279 1;-8836 4279;-9151 4231;-9437 4120 1;-9444 4118;-9450 4114;-9461 4110 1;-9737 3998;-9980 3840;-10181 3635 1;-10185 3631;-10185 3628;-10186 3624 1;-10218 3591;-10250 3536;-10300 3470 1;-10333 3425;-10393 3404;-10450 3423 1;-10505 3440;-10541 3493;-10541 3549 1;-10541 3549;-10541 3724;-10541 3724 1;-10541 3957;-10774 4193;-11008 4191;-11961 4191 1;-12194 4193;-12427 3957;-12427 3724;-12427 1796 1;-12427 1758;-12444 1721;-12472 1697 1;-12501 1670;-12539 1658;-12577 1663 1;-12634 1670;-12689 1668;-12744 1655 1;-12809 1638;-12901 1618;-13015 1597 1;-13021 1595;-13026 1593;-13032 1592 1;-13081 1582;-13101 1582;-13086 1584 1;-13124 1578;-13164 1590;-13194 1615 1;-13224 1640;-13240 1678;-13240 1716;-13240 3724 1;-13240 3957;-13474 4193;-13707 4191;-14660 4191 1;-14893 4193;-15126 3957;-15126 3724;-15126 3532 1;-15126 3476;-15164 3423;-15218 3406 1;-15273 3387;-15335 3408;-15368 3455 1;-15420 3526;-15463 3591;-15511 3643 1;-15517 3651;-15517 3652;-15518 3656 1;-15703 3851;-15933 4002;-16189 4110 1;-16458 4224;-16748 4279;-17051 4279 1;-17346 4279;-17629 4225;-17889 4120 1;-17895 4118;-17902 4114;-17909 4112 1;-18160 4005;-18392 3849;-18580 3651 1;-18586 3643;-18587 3641;-18588 3637 1;-18776 3434;-18919 3196;-19017 2931 1;-19017 2931;-19017 2933;-19019 2927 1;-19122 2648;-19176 2350;-19176 2033 1;-19176 1718;-19123 1419;-19019 1142;-19019 1139 1;-18913 875;-18770 642;-18587 446 1;-18407 241;-18054 35;-17897 -33 1;-17894 -33;-17891 -35;-17889 -37 1;-17628 -143;-17344 -200;-17051 -200 1;-16755 -200;-16468 -143;-16206 -33 1;-15946 76;-15707 235;-15518 433 1;-15470 487;-15425 560;-15368 639 1;-15335 685;-15273 705;-15218 687 1;-15164 669;-15126 617;-15126 559;-15126 538 1;-15126 435;-15088 329;-15023 247 1;-14983 198;-14983 129;-15023 80 1;-15088 -1;-15126 -108;-15126 -211;-15126 -1586 1;-15126 -1644;-15164 -1696;-15218 -1714 1;-15273 -1733;-15335 -1712;-15368 -1666 1;-15420 -1594;-15463 -1529;-15506 -1483 1;-15508 -1478;-15511 -1474;-15517 -1465 1;-15701 -1271;-15928 -1115;-16189 -1005 1;-16463 -889;-16753 -841;-17051 -841 1;-17341 -841;-17624 -888;-17889 -995 1;-17895 -997;-17902 -1001;-17909 -1003 1;-18165 -1113;-18394 -1273;-18578 -1463 1;-18582 -1468;-18582 -1470;-18584 -1474 1;-18586 -1476;-18587 -1479;-18588 -1483 1;-18776 -1684;-18919 -1924;-19019 -2192 1;-19122 -2472;-19176 -2770;-19176 -3085 1;-19176 -3401;-19122 -3698;-19019 -3973 1;-18915 -4238;-18774 -4473;-18586 -4675 1;-18582 -4680;-18580 -4682;-18580 -4684 1;-18577 -4686;-18573 -4688;-18572 -4690 1;-18384 -4883;-18152 -5043;-17897 -5151 1;-17894 -5153;-17891 -5154;-17889 -5156 1;-17628 -5263;-17344 -5317;-17051 -5317 1;-16755 -5317;-16468 -5263;-16204 -5150 1;-15943 -5038;-15707 -4885;-15518 -4684 1;-15468 -4631;-15425 -4560;-15368 -4481 1;-15335 -4433;-15273 -4413;-15218 -4431 1;-15164 -4449;-15126 -4502;-15126 -4560 1;-15126 -4560;-15126 -4648;-15126 -4648 1;-15126 -4840;-14978 -5038;-14794 -5093 1;-14694 -5123;-14598 -5144;-14499 -5165 1;-14499 -5165;-14477 -5168;-14452 -5173 1;-14340 -5198;-14217 -5219;-14085 -5240 1;-13922 -5266;-13842 -5266;-13682 -5281 1;-13547 -5294;-13415 -5306;-13286 -5306 1;-12964 -5306;-12660 -5253;-12380 -5145 1;-12373 -5143;-12371 -5143;-12369 -5143 1;-12101 -5041;-11864 -4883;-11665 -4681 1;-11657 -4671;-11653 -4668;-11649 -4665 1;-11536 -4548;-11441 -4412;-11358 -4260 1;-11334 -4218;-11289 -4192;-11242 -4192 1;-11193 -4192;-11148 -4218;-11125 -4260 1;-11028 -4434;-10923 -4593;-10791 -4726 1;-10600 -4917;-10372 -5065;-10128 -5165 1;-10125 -5165;-10124 -5166;-10118 -5168 1;-9872 -5263;-9613 -5317;-9350 -5317 1;-8783 -5317;-8251 -5120;-7882 -4730 1;-7846 -4691;-7812 -4641;-7767 -4581 1;-7733 -4538;-7676 -4519;-7622 -4536 1;-7569 -4553;-7532 -4600;-7529 -4656 1;-7526 -4846;-7376 -5039;-7192 -5093 1;-6999 -5148;-6777 -5186;-6518 -5226 1;-6513 -5227;-6510 -5229;-6505 -5231 1;-6226 -5276;-5933 -5306;-5630 -5306 1;-5305 -5306;-5020 -5259;-4754 -5153 1;-4499 -5054;-4271 -4908;-4106 -4706 1;-3948 -4513;-3839 -4282;-3777 -4034 1;-3719 -3803;-3694 -3557;-3694 -3294;-3694 -1395 1;-3694 -1161;-3927 -927;-4160 -927;-5113 -927 1;-5263 -927;-5419 -1011;-5502 -1136 1;-5525 -1174;-5569 -1198;-5613 -1198 1;-5660 -1198;-5701 -1174;-5727 -1136 1;-5808 -1012;-5960 -927;-6110 -927;-7063 -927 1;-7220 -929;-7380 -1021;-7459 -1158 1;-7479 -1194;-7516 -1219;-7558 -1224 1;-7599 -1231;-7641 -1216;-7671 -1186 1;-7706 -1151;-7744 -1121;-7790 -1100 1;-7898 -1046;-7976 -1023;-8071 -995 1;-8178 -963;-8281 -942;-8392 -924 1;-8400 -923;-8409 -921;-8417 -920 1;-8419 -918;-8419 -916;-8421 -916 1;-8527 -894;-8644 -874;-8775 -861 1;-8917 -846;-9054 -841;-9183 -841 1;-9523 -841;-9837 -888;-10125 -999 1;-10132 -1003;-10138 -1004;-10148 -1010 1;-10205 -1033;-10261 -1066;-10333 -1102 1;-10380 -1126;-10438 -1119;-10478 -1085 1;-10520 -1051;-10537 -996;-10520 -944 1;-10481 -826;-10453 -709;-10453 -616 1;-10453 -441;-10525 -246;-10637 -67 1;-10667 -20;-10665 40;-10633 84 1;-10575 164;-10541 262;-10541 359;-10541 559 1;-10541 617;-10505 669;-10450 687 1;-10393 705;-10333 685;-10300 639 1;-10233 547;-10171 461;-10103 392 1;-9914 202;-9685 53;-9442 -45 1;-9439 -46;-9435 -48;-9433 -50 1;-9432 -50;-9431 -50;-9429 -50 1;-9183 -144;-8927 -200;-8662 -200 1;-8096 -200;-7562 -1;-7194 386;-7194 386 1;-7192 387;-7194 385;-7194 388 1;-7192 392;-7192 389;-7192 390;-7143 453;-7079 538 1;-7046 581;-6988 598;-6935 581 1;-6882 566;-6846 519;-6843 463 1;-6837 273;-6688 79;-6505 25 1;-6313 -30;-6091 -67;-5824 -110 1;-5540 -156;-5246 -186;-4944 -186 1;-4619 -186;-4332 -142;-4066 -35 1;-3813 64;-3584 211;-3419 414 1;-3404 432;-3387 477;-3347 534 1;-3315 585;-3254 609;-3195 590 1;-3139 574;-3101 519;-3103 459 1;-3103 459;-3103 -482;-3103 -482 1;-3103 -693;-2915 -908;-2706 -941;-1753 -1091 1;-1501 -1129;-1215 -886;-1215 -633;-1215 -241 1;-1215 -166;-1155 -108;-1082 -108;-537 -108 1;-323 -106;-109 82;-79 292 1;-70 342;-35 384;11 399 1;60 415;111 402;147 367 1;333 190;549 49;786 -47 1;1037 -144;1294 -200;1559 -200 1;2126 -200;2658 -1;3027 388 1;3144 513;3239 654;3317 805 1;3338 848;3383 875;3432 875 1;3481 876;3526 852;3550 808 1;3642 654;3737 510;3853 392 1;4045 202;4273 53;4521 -47;4521 -47 1;4521 -48;4520 -46;4522 -47 1;4529 -50;4527 -50;4527 -50 1;4773 -144;5031 -200;5295 -200 1;5861 -200;6394 -1;6763 388 1;6802 432;6839 480;6882 538 1;6914 581;6969 600;7022 585 1;7074 572;7112 529;7119 476 1;7140 310;7271 152;7427 97 1;7615 32;7831 -23;8080 -81 1;8085 -82;8083 -82;8083 -82 1;8360 -146;8654 -178;8965 -178 1;9028 -178;9099 -173;9168 -166 1;9182 -165;9190 -163;9205 -161 1;9278 -156;9347 -148;9415 -136 1;9437 -133;9445 -133;9447 -133 1;9507 -125;9570 -116;9635 -103 1;9681 -95;9728 -112;9758 -146 1;9788 -181;9800 -230;9785 -274 1;9745 -394;9718 -512;9718 -616 1;9718 -878;9838 -1186;10043 -1369 1;10048 -1372;10051 -1374;10058 -1380 1;10243 -1538;10508 -1644;10751 -1644 1;10994 -1644;11257 -1542;11452 -1373 1;11458 -1367;11460 -1365;11466 -1364 1;11671 -1177;11789 -869;11789 -616 1;11789 -441;11717 -246;11606 -67 1;11576 -18;11579 44;11619 94 1;11644 132;11678 151;11716 155 1;11753 159;11791 147;11817 122 1;11871 77;11935 44;12001 25 1;12194 -30;12416 -67;12682 -110 1;12967 -156;13260 -186;13564 -186 1;13889 -186;14173 -142;14439 -35 1;14695 64;14923 211;15088 414 1;15181 529;15253 669;15316 817 1;15337 863;15381 893;15431 897 1;15481 900;15529 874;15555 830 1;15641 673;15739 530;15862 404 1;16061 212;16299 65;16570 -35 1;16849 -140;17147 -186;17457 -186 1;17585 -186;17713 -174;17847 -161 1;17854 -161;17842 -163;17865 -161 1;17990 -153;18110 -138;18237 -120 1;18355 -103;18475 -82;18593 -58 1;18605 -52;18617 -50;18628 -50 1;18743 -26;18848 -1;18940 25 1;19124 80;19273 279;19273 472;19273 3299 1;19273 3915;19111 4466;18724 4844 1;18718 4850;18716 4852;18709 4858 1;18305 5243;17742 5390;17090 5390 18;-1305 3799 1;-1102 3799;-928 3780;-787 3748 1;-646 3712;-518 3673;-404 3626;-539 2884 1;-627 2918;-728 2946;-838 2966 1;-945 2984;-1050 2993;-1151 2993 1;-1365 2993;-1508 2933;-1581 2813 1;-1648 2694;-1683 2535;-1683 2333;-1683 1150;-539 1150;-539 357;-1683 357;-1683 -634;-2636 -481;-2636 2346 1;-2636 2565;-2618 2763;-2579 2941 1;-2536 3121;-2463 3274;-2361 3402 1;-2259 3526;-2123 3624;-1951 3696 1;-1781 3764;-1566 3799;-1305 3799 18;10752 -52 1;10906 -52;11038 -101;11149 -200 1;11264 -303;11323 -441;11323 -616 1;11323 -791;11264 -927;11149 -1026 1;11038 -1128;10906 -1179;10752 -1179 1;10600 -1179;10465 -1128;10350 -1026 1;10238 -927;10183 -791;10183 -616 1;10183 -441;10238 -303;10350 -200 1;10465 -101;10600 -52;10752 -52 18;10279 3722;11233 3722;11233 357;10279 357;10279 3722 18;-11963 3722;-11009 3722;-11009 357;-11963 357;-11963 3722 18;7581 3722;8534 3722;8534 1150 1;8575 1137;8637 1126;8718 1118 1;8804 1105;8877 1098;8937 1098 1;9069 1098;9191 1112;9306 1137 1;9424 1158;9523 1180;9608 1201;9768 414 1;9717 392;9655 375;9583 363 1;9510 345;9437 333;9365 325 1;9292 312;9220 303;9146 299 1;9075 290;9013 286;8962 286 1;8677 286;8415 314;8182 369 1;7950 420;7750 476;7581 536;7581 3722 18;12129 3722;13082 3722;13082 1125 1;13142 1115;13210 1110;13287 1105 1;13363 1097;13435 1092;13504 1092 1;13725 1092;13876 1156;13958 1285 1;14039 1411;14080 1630;14080 1937;14080 3722;15033 3722;15033 1821 1;15033 1592;15010 1381;14963 1195 1;14916 1007;14836 845;14726 709 1;14614 572;14463 467;14272 395 1;14083 318;13847 280;13562 280 1;13280 280;13012 301;12756 344 1;12499 382;12290 425;12129 472;12129 3722 18;15729 3616 1;15737 3607;15749 3596;15758 3588 1;15784 3562;15799 3528;15799 3491 1;15799 3491;15799 3489;15799 3487;15794 3440;15767 3400 1;15769 3404;15763 3384;15737 3354 1;15711 3321;15671 3303;15623 3306 1;15549 3318;15499 3374;15499 3441 1;15499 3441;15499 3524;15499 3524 1;15501 3579;15533 3628;15585 3648 1;15634 3667;15691 3656;15729 3616 18;-14662 3722;-13708 3722;-13708 1150 1;-13667 1137;-13605 1126;-13524 1118 1;-13439 1105;-13366 1098;-13306 1098 1;-13174 1098;-13051 1112;-12936 1137 1;-12819 1158;-12719 1180;-12634 1201;-12474 414 1;-12526 392;-12587 375;-12660 363 1;-12733 345;-12806 333;-12878 325 1;-12951 312;-13022 303;-13096 299 1;-13167 290;-13229 286;-13280 286 1;-13565 286;-13827 314;-14060 369 1;-14292 420;-14492 476;-14662 536;-14662 3722 18;-6378 3722;-5425 3722;-5425 1125 1;-5365 1115;-5297 1110;-5220 1105 1;-5143 1097;-5070 1092;-5002 1092 1;-4780 1092;-4628 1156;-4549 1285 1;-4467 1411;-4427 1630;-4427 1937;-4427 3722;-3474 3722;-3474 1821 1;-3474 1592;-3497 1381;-3544 1195 1;-3591 1007;-3669 845;-3781 709 1;-3890 572;-4042 467;-4235 395 1;-4422 318;-4658 280;-4945 280 1;-5227 280;-5495 301;-5751 344 1;-6007 382;-6217 425;-6378 472;-6378 3722 18;17092 4924 1;17677 4924;18107 4790;18385 4522 1;18665 4257;18806 3849;18806 3299;18806 472 1;18722 446;18624 422;18512 402 1;18405 375;18292 354;18173 337 1;18053 320;17931 307;17809 299 1;17689 286;17572 280;17457 280 1;17187 280;16947 320;16734 402 1;16521 478;16339 589;16189 733 1;16044 878;15934 1053;15857 1259 1;15781 1458;15743 1683;15743 1930 1;15743 2424;15866 2811;16113 3087 1;16361 3361;16717 3498;17182 3498 1;17309 3498;17427 3487;17533 3466 1;17644 3441;17750 3404;17854 3357;17854 3479 1;17854 3666;17796 3819;17680 3939 1;17570 4059;17377 4119;17105 4119 1;16896 4119;16707 4101;16543 4067 1;16379 4032;16224 3986;16074 3926;15908 4725 1;16083 4785;16272 4832;16477 4867 1;16682 4905;16887 4924;17092 4924 18;1726 3810 1;1846 3810;1965 3804;2084 3793 1;2204 3779;2314 3763;2417 3741 1;2524 3724;2619 3703;2705 3677 1;2790 3651;2859 3626;2910 3601;2782 2826 1;2675 2873;2538 2912;2365 2948 1;2199 2978;2029 2993;1854 2993 1;1581 2993;1364 2934;1201 2820 1;1039 2704;947 2550;926 2353;3088 2353 1;3094 2301;3097 2245;3102 2180 1;3105 2112;3109 2050;3109 1995 1;3109 1426;2968 998;2692 709 1;2416 414;2038 267;1559 267 1;1354 267;1154 305;958 382 1;766 459;596 572;446 722 1;298 870;177 1058;81 1285 1;-9 1507;-52 1766;-52 2065 1;-52 2311;-19 2542;49 2756 1;123 2969;231 3154;376 3312 1;524 3466;712 3588;933 3677 1;1159 3765;1422 3810;1726 3810 18;-8496 3810 1;-8376 3810;-8257 3804;-8137 3793 1;-8017 3779;-7908 3763;-7804 3741 1;-7697 3724;-7603 3703;-7516 3677 1;-7431 3651;-7363 3626;-7311 3601;-7440 2826 1;-7546 2873;-7684 2912;-7855 2948 1;-8022 2978;-8193 2993;-8368 2993 1;-8640 2993;-8857 2934;-9020 2820 1;-9182 2704;-9273 2550;-9296 2353;-7132 2353 1;-7128 2301;-7124 2245;-7119 2180 1;-7116 2112;-7113 2050;-7113 1995 1;-7113 1426;-7252 998;-7529 709 1;-7806 414;-8184 267;-8662 267 1;-8867 267;-9067 305;-9264 382 1;-9455 459;-9625 572;-9775 722 1;-9923 870;-10045 1058;-10140 1285 1;-10230 1507;-10273 1766;-10273 2065 1;-10273 2311;-10240 2542;-10171 2756 1;-10098 2969;-9990 3154;-9845 3312 1;-9696 3466;-9510 3588;-9288 3677 1;-9062 3765;-8798 3810;-8496 3810 18;-12484 -146 1;-12454 -181;-12442 -230;-12457 -274 1;-12497 -394;-12524 -512;-12524 -616 1;-12524 -619;-12502 -670;-12491 -753 1;-12484 -794;-12496 -836;-12524 -866 1;-12554 -896;-12594 -911;-12640 -905 1;-12765 -882;-12886 -866;-13002 -866 1;-13009 -866;-13043 -876;-13102 -878 1;-13139 -879;-13174 -866;-13199 -841 1;-13225 -814;-13240 -781;-13240 -745 1;-13240 -745;-13240 -300;-13240 -300 1;-13240 -230;-13188 -171;-13119 -166 1;-13079 -161;-13064 -165;-13074 -166;-13056 -164;-13037 -161 1;-12964 -156;-12895 -148;-12827 -136 1;-12806 -133;-12797 -133;-12795 -133;-12795 -132;-12793 -132;-12795 -133 1;-12735 -125;-12673 -116;-12607 -103 1;-12561 -95;-12514 -112;-12484 -146 18;-14662 -213;-13708 -213;-13708 -1479 1;-13602 -1432;-13492 -1395;-13377 -1371 1;-13261 -1346;-13137 -1333;-13006 -1333 1;-12765 -1333;-12556 -1376;-12373 -1461 1;-12189 -1546;-12034 -1666;-11911 -1819 1;-11788 -1972;-11694 -2156;-11629 -2368 1;-11566 -2582;-11535 -2819;-11535 -3078 1;-11535 -3348;-11574 -3591;-11657 -3808 1;-11732 -4027;-11846 -4210;-11995 -4358 1;-12144 -4513;-12328 -4630;-12544 -4711 1;-12763 -4796;-13009 -4838;-13287 -4838 1;-13402 -4838;-13524 -4833;-13652 -4819 1;-13776 -4811;-13898 -4798;-14022 -4781 1;-14142 -4765;-14257 -4743;-14369 -4716 1;-14478 -4697;-14576 -4673;-14662 -4646;-14662 -213 18;-17051 3810 1;-16800 3810;-16574 3769;-16373 3684 1;-16168 3598;-15993 3479;-15848 3324 1;-15703 3168;-15593 2980;-15517 2763 1;-15440 2540;-15401 2298;-15401 2033 1;-15401 1768;-15442 1526;-15523 1310 1;-15603 1092;-15716 906;-15861 754 1;-16006 600;-16182 480;-16386 395 1;-16586 310;-16808 267;-17051 267 1;-17291 267;-17512 310;-17717 395 1;-17917 480;-18092 600;-18242 754 1;-18387 906;-18502 1092;-18587 1310 1;-18669 1526;-18708 1768;-18708 2033 1;-18708 2298;-18669 2540;-18587 2763 1;-18505 2980;-18392 3168;-18247 3324 1;-18102 3479;-17931 3598;-17729 3684 1;-17525 3769;-17299 3810;-17051 3810 18;5463 3810 1;5581 3810;5701 3804;5821 3793 1;5939 3779;6051 3763;6152 3741 1;6259 3724;6356 3703;6441 3677 1;6526 3651;6594 3626;6646 3601;6518 2826 1;6411 2873;6272 2912;6103 2948 1;5936 2978;5765 2993;5590 2993 1;5318 2993;5100 2934;4938 2820 1;4775 2704;4683 2550;4663 2353;6826 2353 1;6829 2301;6834 2245;6837 2180 1;6843 2112;6844 2050;6844 1995 1;6844 1426;6706 998;6428 709 1;6151 414;5773 267;5297 267 1;5091 267;4891 305;4695 382 1;4503 459;4332 572;4183 722 1;4033 870;3911 1058;3819 1285 1;3729 1507;3684 1766;3684 2065 1;3684 2311;3719 2542;3787 2756 1;3858 2969;3967 3154;4112 3312 1;4262 3466;4446 3588;4668 3677 1;4895 3765;5160 3810;5463 3810 18;-1065 2521 1;-1018 2518;-969 2518;-911 2508 1;-910 2508;-909 2506;-907 2505 1;-830 2489;-762 2473;-704 2450 1;-702 2450;-700 2450;-698 2450 1;-670 2439;-642 2426;-612 2422 1;-545 2409;-500 2350;-503 2283 1;-509 2203;-520 2131;-520 2067 1;-520 1973;-502 1875;-490 1763 1;-487 1725;-500 1688;-525 1660 1;-550 1633;-586 1616;-623 1616;-1106 1616 1;-1170 1630;-1217 1687;-1215 1750;-1215 2333 1;-1215 2360;-1211 2386;-1206 2405 1;-1198 2474;-1136 2527;-1065 2521 18;-11490 -52 1;-11336 -52;-11204 -101;-11093 -200 1;-10978 -303;-10920 -441;-10920 -616 1;-10920 -791;-10978 -927;-11093 -1026 1;-11204 -1128;-11336 -1179;-11490 -1179 1;-11642 -1179;-11777 -1128;-11893 -1026 1;-12004 -927;-12059 -791;-12059 -616 1;-12059 -441;-12004 -303;-11893 -200 1;-11777 -101;-11642 -52;-11490 -52 18;-17051 -1307 1;-16800 -1307;-16574 -1349;-16373 -1434 1;-16168 -1521;-15993 -1639;-15848 -1794 1;-15703 -1951;-15593 -2139;-15517 -2355 1;-15440 -2579;-15401 -2820;-15401 -3085 1;-15401 -3350;-15442 -3591;-15523 -3808 1;-15603 -4027;-15716 -4211;-15861 -4365 1;-16006 -4518;-16182 -4638;-16386 -4723 1;-16586 -4808;-16808 -4851;-17051 -4851 1;-17291 -4851;-17512 -4808;-17717 -4723 1;-17917 -4638;-18092 -4518;-18242 -4365 1;-18387 -4211;-18502 -4027;-18587 -3808 1;-18669 -3591;-18708 -3350;-18708 -3085 1;-18708 -2820;-18669 -2579;-18587 -2355 1;-18505 -2139;-18392 -1951;-18247 -1794 1;-18102 -1639;-17931 -1521;-17729 -1434 1;-17525 -1349;-17299 -1307;-17051 -1307 18;-7064 -1395;-6112 -1395;-6112 -3993 1;-6052 -4004;-5983 -4008;-5907 -4013 1;-5830 -4021;-5759 -4027;-5690 -4027 1;-5468 -4027;-5317 -3961;-5235 -3833 1;-5155 -3707;-5113 -3488;-5113 -3182;-5113 -1395;-4160 -1395;-4160 -3296 1;-4160 -3527;-4183 -3737;-4230 -3923 1;-4277 -4111;-4357 -4273;-4467 -4410 1;-4579 -4547;-4730 -4652;-4921 -4723 1;-5110 -4800;-5347 -4838;-5631 -4838 1;-5913 -4838;-6181 -4818;-6438 -4774 1;-6694 -4736;-6903 -4693;-7064 -4646;-7064 -1395 18;-11099 -1644 1;-11068 -1689;-11067 -1748;-11095 -1794 1;-11120 -1834;-11128 -1842;-11120 -1827 1;-11143 -1872;-11189 -1899;-11242 -1899 1;-11246 -1897;-11251 -1895;-11258 -1894 1;-11298 -1887;-11332 -1862;-11353 -1827 1;-11358 -1822;-11364 -1814;-11375 -1799 1;-11394 -1761;-11396 -1718;-11379 -1679 1;-11362 -1639;-11328 -1611;-11287 -1602 1;-11257 -1596;-11240 -1594;-11242 -1594 1;-11188 -1581;-11133 -1601;-11099 -1644 18;-9182 -1307 1;-9063 -1307;-8944 -1314;-8824 -1326 1;-8706 -1339;-8594 -1356;-8492 -1378 1;-8385 -1395;-8289 -1416;-8204 -1440 1;-8119 -1468;-8051 -1493;-7999 -1517;-8127 -2292 1;-8234 -2246;-8372 -2205;-8542 -2171 1;-8708 -2141;-8881 -2126;-9055 -2126 1;-9327 -2126;-9545 -2184;-9707 -2299 1;-9870 -2413;-9961 -2569;-9982 -2766;-7819 -2766 1;-7816 -2817;-7810 -2873;-7808 -2939 1;-7803 -3007;-7801 -3069;-7801 -3123 1;-7801 -3692;-7939 -4120;-8217 -4410 1;-8494 -4705;-8872 -4851;-9349 -4851 1;-9553 -4851;-9754 -4813;-9950 -4736 1;-10141 -4660;-10314 -4547;-10462 -4396 1;-10611 -4248;-10733 -4060;-10827 -3833 1;-10917 -3612;-10962 -3352;-10962 -3054 1;-10962 -2807;-10926 -2575;-10858 -2362 1;-10787 -2149;-10678 -1964;-10533 -1806 1;-10383 -1652;-10198 -1530;-9976 -1440 1;-9750 -1352;-9485 -1307;-9182 -1307 18;16428 5964 1;15493 5816;15156 5633;14905 5136 1;14842 5010;14767 4893;14739 4875 1;14686 4843;13829 4769;13588 4777 1;13511 4779;12673 4786;11726 4791;10003 4801;9412 4491;8810 4801;8189 4815 1;7703 4826;7501 4814;7261 4759 1;6957 4690;6950 4690;6521 4785 1;6170 4863;5974 4881;5488 4880;5457 4880 1;4811 4880;4563 4831;4074 4600 1;3912 4524;3745 4461;3703 4461 1;3660 4461;3540 4504;3437 4556 1;2881 4838;1858 4973;1148 4859 1;1005 4835;741 4765;560 4703 1;206 4579;201 4579;-280 4737 1;-640 4854;-1173 4915;-1564 4883 1;-1876 4858;-2085 4806;-2522 4644 1;-2687 4583;-2700 4585;-2962 4691 1;-3221 4796;-3260 4801;-3912 4799 1;-4286 4797;-4700 4791;-4832 4785 1;-4964 4779;-5368 4786;-5729 4802 1;-6286 4827;-6433 4820;-6697 4760 1;-7003 4690;-7012 4690;-7420 4779 1;-8263 4964;-9117 4926;-9699 4679 1;-10091 4513;-10177 4511;-10482 4666;-10748 4801;-12238 4801;-12541 4645;-12844 4489;-13138 4645;-13432 4801;-14922 4801;-15208 4663 1;-15529 4507;-15467 4502;-16152 4744 1;-16831 4984;-17621 4945;-18238 4642 1;-19010 4261;-19482 3685;-19691 2865 1;-19908 2013;-19801 1156;-19391 468 1;-19227 194;-19067 14;-18762 -238 1;-18460 -488;-18462 -552;-18772 -793 1;-19030 -993;-19347 -1393;-19507 -1720 1;-19700 -2113;-19789 -2552;-19789 -3099 1;-19788 -3688;-19727 -3966;-19489 -4450 1;-19192 -5057;-18572 -5590;-17912 -5806 1;-17374 -5984;-16546 -5988;-15770 -5633;-15447 -5485;-15239 -5576 1;-14740 -5794;-14092 -5908;-13352 -5909 1;-12569 -5909;-12118 -5779;-11532 -5381 1;-11433 -5314;-11315 -5259;-11270 -5259 1;-11225 -5259;-11047 -5352;-10875 -5465 1;-10015 -6029;-9078 -6079;-8023 -5616;-7813 -5524;-7443 -5648 1;-6638 -5917;-5482 -5996;-4840 -5824 1;-4236 -5663;-3768 -5339;-3467 -4873 1;-3148 -4378;-3090 -4073;-3064 -2779 1;-3052 -2196;-3026 -1687;-3006 -1649 1;-2959 -1560;-2787 -1559;-2312 -1644 1;-2114 -1679;-1835 -1709;-1691 -1709 1;-1229 -1712;-888 -1486;-654 -1024 1;-541 -799;-528 -788;-245 -681 1;187 -519;243 -518;668 -662 1;965 -763;1135 -795;1448 -809 1;2091 -837;2566 -704;3131 -337 1;3264 -250;3400 -179;3432 -179 1;3464 -179;3619 -259;3777 -358 1;4137 -581;4287 -644;4688 -741 1;5298 -888;5896 -821;6519 -534;6870 -372;7177 -478 1;7625 -633;8076 -733;8550 -781 1;9020 -829;9105 -876;9182 -1133 1;9308 -1554;9694 -1943;10095 -2129 1;10456 -2299;11045 -2279;11428 -2095 1;11880 -1878;12170 -1593;12329 -1108 1;12441 -766;12455 -756;12815 -779 1;14010 -855;14639 -730;15238 -297 1;15327 -232;15435 -179;15479 -179 1;15522 -179;15686 -258;15843 -355 1;16603 -824;17454 -922;18651 -679 1;19204 -567;19417 -469;19628 -230 1;19900 79;19908 145;19908 1951;19908 2068 1;19908 3651;19886 3934;19718 4401 1;19503 5000;19140 5402;18544 5703 1;18007 5974;17155 6079;16428 5964 18;17928 5561 1;18700 5363;19232 4845;19456 4071 1;19512 3877;19525 3576;19538 2141 1;19550 942;19541 396;19509 289 1;19438 50;19214 -170;18973 -238 1;18265 -438;17233 -498;16751 -367 1;16348 -257;15993 -62;15706 208;15444 456;15306 271 1;15116 17;14791 -194;14388 -327 1;14080 -428;13997 -439;13508 -436 1;13048 -433;12442 -364;12083 -274 1;12000 -253;11998 -259;12035 -436 1;12080 -647;12030 -945;11908 -1199 1;11636 -1762;10897 -2045;10292 -1817 1;9806 -1635;9468 -1148;9468 -632;9468 -407;9216 -431 1;8866 -464;8256 -399;7783 -280 1;7323 -163;7201 -108;7046 57;6934 175;6772 37 1;5907 -704;4382 -591;3607 271;3424 474;3360 377 1;3119 21;2522 -336;2023 -420 1;1440 -518;756 -394;341 -114;129 29;28 -91 1;-139 -289;-354 -379;-661 -379;-932 -379;-932 -509 1;-933 -750;-1017 -955;-1187 -1124 1;-1437 -1374;-1550 -1391;-2246 -1283 1;-2569 -1232;-2887 -1163;-2953 -1129 1;-3248 -975;-3372 -718;-3372 -258;-3372 65;-3550 -58 1;-3801 -230;-4065 -337;-4405 -402 1;-4781 -475;-5094 -474;-5671 -398 1;-6502 -289;-6766 -202;-6943 24;-7040 149;-7232 3 1;-7499 -201;-7690 -292;-8042 -381 1;-8755 -564;-9576 -395;-10120 47 1;-10278 175;-10291 178;-10328 108 1;-10358 53;-10348 -23;-10289 -176 1;-10246 -291;-10206 -465;-10202 -563 1;-10196 -705;-10182 -736;-10133 -716 1;-9610 -509;-8452 -550;-7836 -799 1;-7626 -884;-7587 -889;-7532 -839 1;-7372 -694;-7184 -659;-6575 -659;-6548 -659 1;-5984 -659;-5837 -684;-5685 -810 1;-5627 -859;-5602 -854;-5492 -772 1;-5374 -686;-5322 -678;-4739 -666 1;-4055 -652;-3888 -680;-3692 -845 1;-3432 -1064;-3432 -1066;-3434 -2479 1;-3436 -3540;-3448 -3805;-3503 -4029 1;-3693 -4791;-4168 -5277;-4922 -5483 1;-5261 -5575;-6112 -5566;-6698 -5463 1;-7272 -5363;-7461 -5289;-7610 -5109;-7726 -4968;-7879 -5088 1;-8814 -5825;-10355 -5685;-11073 -4798;-11235 -4596;-11494 -4860 1;-11783 -5155;-12156 -5370;-12572 -5482 1;-13108 -5626;-14450 -5523;-14960 -5299 1;-15058 -5256;-15175 -5160;-15239 -5069;-15350 -4913;-15611 -5103 1;-16440 -5704;-17556 -5733;-18389 -5176 1;-18763 -4926;-18970 -4689;-19174 -4279 1;-19544 -3536;-19541 -2623;-19167 -1859 1;-18698 -903;-17669 -417;-16549 -623 1;-16267 -675;-15788 -888;-15574 -1057;-15421 -1179;-15405 -589 1;-15394 -169;-15373 26;-15332 89 1;-15235 239;-15319 237;-15504 86 1;-16274 -546;-17402 -634;-18285 -132 1;-19617 624;-19853 2734;-18732 3863 1;-17912 4689;-16505 4772;-15566 4050;-15379 3907;-15333 4019 1;-15270 4170;-15105 4323;-14923 4399 1;-14712 4487;-13672 4487;-13461 4399 1;-13264 4317;-13137 4195;-13048 4001 1;-12982 3860;-12974 3728;-12973 2871;-12973 2823 1;-12972 1843;-12978 1874;-12782 1926;-12692 1950 1;-12692 3973;-12680 4038;-12439 4250 1;-12222 4440;-12067 4471;-11387 4455 1;-10804 4441;-10780 4438;-10624 4329 1;-10492 4238;-10413 4134;-10306 3908 1;-10303 3901;-10213 3963;-10106 4044 1;-9632 4408;-9047 4566;-8312 4528 1;-7825 4503;-7365 4416;-7096 4297 1;-6933 4226;-6914 4225;-6848 4284 1;-6702 4417;-6483 4457;-5908 4459 1;-5355 4461;-5138 4426;-5010 4317 1;-4958 4272;-4918 4279;-4753 4362 1;-4571 4454;-4518 4461;-3955 4460 1;-3267 4459;-3106 4414;-2910 4168;-2797 4027;-2623 4147 1;-2311 4362;-2052 4456;-1635 4505 1;-1021 4577;-348 4454;37 4200;186 4101;437 4238 1;800 4435;1069 4503;1588 4529 1;1962 4547;2134 4535;2508 4464 1;3072 4358;3355 4230;3495 4017 1;3552 3931;3607 3861;3617 3861 1;3627 3861;3710 3925;3802 4004 1;4053 4219;4484 4414;4868 4487 1;5440 4594;6391 4505;6861 4299;7033 4223;7198 4332 1;7357 4438;7382 4441;8005 4453 1;8611 4465;8658 4460;8826 4373 1;8923 4323;9058 4212;9126 4127;9248 3974;9260 2937;9272 1901;9360 1902 1;9541 1903;9543 1914;9556 2969;9568 3974;9690 4127 1;9758 4212;9892 4322;9989 4371 1;10149 4453;10221 4461;10767 4460 1;11260 4459;11397 4446;11528 4387 1;11682 4317;11694 4317;11848 4387 1;11979 4446;12117 4459;12611 4460 1;13162 4461;13230 4453;13396 4369;13577 4278;13732 4359 1;13871 4432;13961 4441;14551 4441;15214 4441;15197 4626 1;15173 4869;15240 5059;15408 5233 1;15568 5397;15799 5483;16366 5586 1;16835 5672;17538 5661;17928 5561;17928 5561 18;-13184 -2139 1;-13282 -2139;-13381 -2152;-13479 -2177 1;-13572 -2202;-13648 -2234;-13708 -2274;-13708 -3993 1;-13662 -4004;-13602 -4008;-13530 -4013 1;-13457 -4021;-13379 -4027;-13293 -4027 1;-13032 -4027;-12837 -3936;-12704 -3756 1;-12572 -3582;-12506 -3348;-12506 -3054 1;-12506 -2443;-12733 -2139;-13184 -2139 18;-13248 -2631 1;-13034 -2631;-12976 -2876;-12976 -3090 1;-12976 -3284;-13054 -3505;-13248 -3506;-13248 -2631 18;17360 2730 1;16930 2730;16714 2463;16714 1930 1;16714 1675;16776 1464;16900 1297 1;17024 1130;17212 1047;17464 1047 1;17548 1047;17623 1052;17687 1060 1;17750 1065;17807 1072;17854 1080;17854 2603 1;17794 2636;17720 2666;17636 2691 1;17550 2718;17459 2730;17360 2730 18;17409 2232;17409 1571 1;17201 1492;17180 1713;17180 1926 1;17178 2120;17192 2338;17409 2232 18;69180 53168 1;69435 53137;69705 53115;70028 53115 1;71160 53123;71678 53512;72750 53895 1;73958 54345;74580 54570;75870 54750 1;76800 54893;77460 54863;78090 55575 1;78675 56250;79028 56685;79148 57570 1;79200 58012;79260 58245;79185 58673 1;79065 59325;79095 59670;79230 60315 1;79320 60802;79320 61162;79725 61433 1;80370 61875;80768 62205;81548 62130 1;82448 62063;82815 61500;83730 61515 1;84795 61530;85328 61635;86408 61613 1;87367 61605;87908 61455;88725 60930 1;89160 60660;89250 60270;89265 59753 1;89280 59250;89115 58995;88830 58575 1;88418 58005;88110 57802;87585 57330 1;86760 56610;86265 56325;85568 55470 1;84998 54810;84548 54585;84165 53790 1;83798 53055;83708 52620;83625 51795 1;83505 50700;83175 50190;82770 49170 1;81855 46980;81068 46020;80310 43770 1;80055 43050;79905 42570;80227 41873 1;80288 41738;80348 41610;80408 41490;69210 50662 1;70268 50715;70867 50573;71850 50992 1;72825 51435;73275 51742;74310 52073 1;75188 52373;75645 52485;76530 52815 1;77227 53085;77828 53085;78390 52575 1;78795 52200;78720 51780;78750 51210 1;78780 50302;78600 49815;78165 48990 1;77678 48090;77310 47700;76905 46755 1;76178 45053;75780 44130;75727 42270 1;75690 41213;75803 40545;75938 39488;69210 46020 1;69480 45923;69705 45750;69908 45450 1;70110 45150;70200 44963;70208 44595 1;70215 44025;70005 43755;69870 43193 1;69675 42525;69518 42135;69218 41603;89265 73830 1;89040 73545;88575 73223;88387 73530 1;88178 73875;88058 74242;88350 74512 1;88620 74783;89025 75135;89250 74813 1;89468 74483;89520 74123;89265 73830 18;69158 62535 1;69255 62512;69360 62505;69488 62512 1;70035 62565;70418 62700;70710 63173 1;71048 63750;71025 64140;71430 64673 1;72488 66120;73155 66795;74610 67852 1;75338 68393;75878 68355;76770 68573 1;77617 68790;77977 69105;78788 69450 1;79515 69780;80025 69713;80648 70230 1;81015 70560;81278 70673;81525 71093 1;81698 71400;81885 71602;82245 71595 1;82710 71595;82890 71265;83145 70875 1;83318 70605;83408 70470;83588 70193 1;83790 69885;84240 69840;84510 70095 1;85410 70950;85808 71445;86768 72233 1;87105 72525;87135 72960;86910 73335 1;86745 73583;86655 73733;86685 74010 1;86730 74415;86895 74610;87210 74873 1;87825 75420;88005 75893;88770 76253 1;89190 76463;89550 76665;89948 76395 1;90367 76102;90660 75833;90668 75315 1;90668 74573;90218 74242;90270 73492 1;90315 72563;90398 71970;91050 71295 1;91598 70710;91830 70320;92550 69930 1;93330 69525;93885 69713;94770 69870 1;95378 69990;95700 70125;96330 70095 1;96960 70073;97320 69713;97590 69135 1;97958 68303;98130 67875;98430 66990 1;98595 66473;98895 66075;99450 66075 1;99990 66075;100260 66285;100688 66615 1;101085 66938;101325 67170;101580 67492;118417 37920 1;118410 38063;118380 38213;118328 38370 1;118087 38993;118058 39495;117465 39773 1;117158 39923;116977 39983;116648 39975 1;116085 39960;115306 39791;115276 39235 1;115216 38718;115180 38397;115188 37880 1;115188 37647;115233 37370;115285 37190 16;115709 37870 1;115822 35231;118914 37371;117405 38895 1;117106 39197;116122 39241;115920 38864 1;115769 38587;115717 38117;115709 37870 18;69150 64305 1;69563 64448;69893 64695;70290 65070 1;71025 65813;71355 66225;72090 66975 1;72727 67643;73020 68003;73748 68573 1;74280 69000;74528 69293;75188 69495 1;76020 69765;76530 69593;77325 69953 1;78225 70373;78615 70740;79568 71055 1;80325 71310;80760 71483;81330 72053 1;81675 72413;81818 72803;82328 72810 1;82665 72825;82785 72555;82988 72270 1;83227 71933;83400 71790;83685 71475 1;83925 71190;84345 71220;84630 71475 1;85028 71850;85298 71970;85665 72390 1;85988 72773;86175 73193;85928 73613 1;85725 73950;85770 74220;85928 74573 1;86137 75060;86205 75352;86588 75735 1;86940 76110;88180 76923;88676 77100;123225 70193 1;123585 69495;123690 69105;124005 68370 1;124193 67950;124335 67598;124455 67260;124477 61650 1;124260 61403;124012 61170;123788 60810 1;123045 59693;122715 59085;121785 58110 1;120637 56925;119948 56430;118590 55492 1;117360 54660;116925 53963;115650 53213 1;114878 52785;114405 52755;113610 52395 1;113167 52215;112928 52162;112485 52012 1;112087 51885;112005 51600;111705 51315 1;111330 50970;111045 50805;110565 50738;69158 66120 1;70035 66585;70410 67028;71168 67733 1;71970 68505;72390 68873;73305 69495 1;73770 69810;74040 69930;74565 70133 1;75637 70553;76268 70575;77227 71213 1;77985 71730;78495 71745;79365 72030 1;79680 72150;79800 72315;80048 72533 1;80430 72893;80588 73170;81090 73350 1;81578 73545;81795 73800;82328 73815 1;82755 73830;83010 73635;83288 73290 1;83558 72960;83580 72653;83970 72450 1;84420 72225;84930 72690;85005 73193 1;85065 73695;85080 73950;85028 74453 1;84990 74790;85178 74955;85365 75233 1;85695 75765;85808 76080;86288 76470 1;86820 76920;87038 77250;87690 77490 1;88125 77670;88448 77843;88793 77963;90428 77963 1;90945 77745;91283 77288;91710 76733 1;92460 75750;92745 75113;92887 73875 1;92977 72975;93375 72473;94148 71970 1;94358 71843;94530 71895;94785 71895 1;95528 71903;96098 72030;96750 71655 1;97215 71385;97425 71280;97770 70830 1;98137 70335;98460 70193;98805 69653 1;99368 68835;99630 69180;99870 69533 1;100455 70170;100815 70373;101430 70890 1;101970 71370;102398 71385;103065 71655 1;103935 72023;104408 72150;105345 72315 1;106118 72450;106598 72690;107310 72352 1;107962 72120;108308 71955;109005 71963 1;110018 71985;110655 71970;111465 72578 1;111870 72893;111953 73185;112148 73658 1;112230 73867;112245 74010;112470 74190;112470 74190 1;113730 74700;114465 74805;115830 74730 1;116505 74700;116917 74760;117525 74430;118403 72773 1;118950 72383;119340 71955;119962 71685 1;120623 71408;121058 71445;121762 71258 1;122370 71100;122663 70973;123218 70665 1;123818 70335;124102 69915;124448 69495;124485 55560 1;123878 55058;123225 54563;122370 53970 1;121335 53280;120968 52733;119910 52095 1;118748 51412;118170 51052;116910 50610 1;116258 50393;115905 50340;115230 50250 1;114735 50205;114698 49650;114225 49575 1;113220 49410;112740 49200;111727 49110 1;110265 48990;109628 48233;108172 48278 1;107595 48278;106748 48525;106005 48375 1;105525 48285;105225 48412;104805 48173 1;104108 47790;103837 47430;103087 47152 1;102420 46920;102278 46793;101768 46545;96285 77977 1;96990 77573;97290 77123;98070 76650 1;98887 76163;99315 75653;100290 75690 1;101137 75742;101528 76200;102390 76155 1;102945 76133;103215 75900;103785 75930 1;104325 75975;104587 76080;105105 76230 1;105990 76492;106448 76665;107370 76650 1;107730 76650;107895 76523;108270 76455 1;108525 76365;108503 76088;108503 75810 1;108495 75203;108383 75188;108637 74625 1;108818 74220;109028 73823;109477 73808 1;109995 73800;110333 73733;110753 74048 1;111000 74242;111098 74400;111188 74708 1;111308 75180;111315 75158;111428 75623 1;111488 75893;111555 76155;111833 76178 1;112080 76208;112208 76193;112425 76230;102600 78008 1;102758 77933;102915 77858;103087 77775 1;103920 77370;104348 77040;105285 77010 1;106365 76980;106875 77565;107970 77475 1;108360 77453;108585 77355;108870 77070 1;109328 76613;109005 76110;109050 75450 1;109087 74745;109170 74378;109890 74378 1;110520 74393;110715 74640;110835 75262 1;110970 75998;111113 76230;111368 76928 1;111503 77310;111975 77130;112328 77333 1;112920 77685;113250 77887;113903 78038;116400 78045 1;116535 78000;116678 77940;116843 77873 1;117637 77543;118163 77310;118973 77018 1;119670 76778;119648 75585;120068 75315 1;121350 74498;122227 74490;123570 73305;112425 76230 1;113490 76433;114360 76590;115425 76770 1;116648 76995;117413 77085;118628 76575 1;118695 76545;118485 76448;118575 76178 1;119385 73665;121815 74250;123698 72578;112605 75833 1;114165 76102;115297 76320;116887 76433 1;117480 76485;117795 76463;118387 76335 1;118328 76185;118178 76020;118200 75848 1;118553 73005;121020 74085;122753 72668;112065 74940 1;112163 75173;112358 75218;112605 75270 1;113805 75465;114405 75653;115628 75735 1;116505 75803;117015 75960;117893 75833 1;117953 75750;117810 75262;117848 75165 1;118680 72945;120518 73215;122558 72225 1;123270 71880;123750 71760;124440 71588;111975 74288 1;112065 74617;112253 74805;112590 74873 1;113655 75015;114188 75180;115268 75210 1;116190 75255;116655 75352;117585 75233;124508 52380 1;123735 52012;123098 51855;122205 51315 1;121118 50670;120525 50400;119325 50010 1;118508 49762;118095 49530;117488 48930 1;116887 48360;116475 48113;115665 47955 1;113558 47558;112320 47633;110542 47483;119858 78060 1;120615 77745;121297 77460;122250 76950 1;122783 76673;122962 76275;123060 75675 1;123188 74887;123337 74242;124095 73965;124508 49733 1;124073 49598;123623 49433;123060 49223 1;121620 48720;120990 48255;119580 47700 1;117150 46785;115725 46980;113137 46980;123428 34110 1;123525 34253;123623 34410;123727 34590 1;123998 35145;124095 35565;124560 35858;124523 43883 1;124208 43995;123870 44108;123465 44250 1;122137 44723;121448 44910;120068 45150 1;119010 45345;118477 45443;117428 45615 1;117098 45675;116850 45825;116528 45893 1;116318 45953;116408 46275;116625 46290 1;116828 46320;116940 46260;117150 46290 1;118883 46223;120038 46088;121410 46133 1;122025 46148;123188 46193;123465 46313;124523 34110;124560 34193;124530 44453 1;124065 44550;123765 44648;123270 44835 1;122400 45150;121928 45195;121087 45533 1;120848 45630;120660 45720;120922 45750 1;122415 45938;123428 45938;124523 45930;123465 46313 1;123885 46530;124215 46748;124523 46957;124433 71933 1;124260 71977;124087 72023;123922 72075;124425 72308;124305 72352;69240 38070 1;70613 38243;71858 38415;73665 38580 1;75585 38760;75908 38355;77400 38415 1;79485 38505;80453 38595;82485 38850 1;83205 38948;83580 38948;84293 39120 1;85125 39330;85650 39510;86137 40215 1;86843 41258;87262 41730;88043 42720 1;88538 43365;89115 43740;89925 43770 1;93262 44070;94875 44228;98235 44820 1;99458 45098;100065 45188;101235 45660 1;102810 46215;103493 47115;105225 47160 1;107340 47220;108435 47115;110505 46620 1;112575 46125;113655 46148;115785 46050 1;118568 45930;119925 45743;122715 45630 1;123428 45608;123983 45623;124530 45593;69128 68242 1;69308 68363;69495 68490;69698 68625 1;73380 71183;74985 72203;78578 74783 1;80258 76043;81083 76725;82590 77948;103875 57915;116363 62985 1;114788 62738;112905 62512;111352 62183 1;110310 61965;108975 61800;107873 61568;74175 70159;79778 53235 1;81008 53250;82470 53730;84465 54450 1;86250 55103;87623 55125;89205 54060 1;90383 53265;91125 52838;92483 52380 1;94335 51840;95235 52020;97365 52230 1;97823 52275;98220 52320;98595 52365;109912 65477;106598 63218 32;107783 61733;107137 74783 1;107453 73980;107460 73492;107962 72773 1;108240 72375;108555 72262;109058 72233 1;109410 72225;109650 72323;109898 72367 1;110145 72405;110408 72390;110723 72488 1;111143 72645;111337 72870;111630 73208 1;111795 73410;111810 73560;111893 73808 1;111998 74175;112073 75045;112080 75405;69195 48818 1;69338 48570;69488 48308;69645 48030;83918 39030 1;84930 38970;85658 38850;86468 39465 1;87083 39945;87518 40027;88298 40005 1;89693 39975;90390 40058;91793 40110 1;93105 40162;94538 40350;95858 40320;87727 42300 1;86985 41318;88560 40088;89798 40020;102909 57261 1;100884 56076;98760 55335;96285 53693 1;95048 52890;94515 52545;93480 51938;103515 59340;69195 47918 1;69293 47955;69390 47993;69495 48030;69120 74693;69383 74865 32;69120 72308;69120 74693 18;69293 54375 1;69255 54443;69218 54510;69180 54578;98715 77992;99255 77775 32;98858 76800 32;97913 77168;98235 77992;98715 77992 18;74115 38700 1;73852 40298;73815 41198;72975 42570 1;71633 44760;70973 45870;69645 48060;79605 53550 1;77198 55988;75975 57090;73665 59610 1;72218 61185;71602 61943;70125 63480 1;69720 63908;69360 64283;69143 64733;69645 48060 1;70913 48683;71558 48938;72825 49500 1;74303 50168;75158 50332;76485 51270 1;77550 52035;78225 52238;79185 53130 1;79313 53258;79433 53378;79545 53490 33;80258 54203;80640 54742;81248 55710 1;81923 56820;82463 57270;83543 57990 1;84773 58823;85313 59393;86678 59970 1;88073 60570;88958 60750;90458 60450 1;92415 60068;93488 60255;95498 60255 1;96413 60240;96795 60195;97688 60225 1;98685 60262;99060 60270;100178 60495 1;101903 60840;102045 60870;103095 60668 1;103477 60608;103485 60668;103890 60758 1;104520 60908;104895 61207;105547 61215 1;106133 61230;106387 61253;107003 61343 1;107348 61403;107610 61485;107887 61568;74025 39420 1;74700 41183;75150 42030;76125 43650 1;76898 44948;77310 45608;78405 46650 1;79515 47723;81060 48203;82485 48810;79605 53370 1;80010 52973;80190 52755;80595 52350 1;81023 51923;81045 51555;81225 50970 1;81413 50348;81510 50040;81705 49410 1;81803 49080;81683 48878;81585 48540;69188 54360 1;69840 54495;70433 54315;70988 54293 1;71648 54278;72435 54427;72968 54353 1;73688 54262;74025 54128;75045 53910 1;76635 53610;77205 53580;79275 53310;69240 37838 1;69750 37568;70463 37065;70838 36750 1;71558 36158;73110 34868;74227 33953;76845 38490 1;77003 37665;77100 37253;77265 36420 1;77445 35460;77617 34733;77670 33960;73703 52598;75953 54615;112530 47799;103395 60720 1;103598 59880;104025 59588;104505 58860 1;105053 58035;105570 57585;105735 56595 1;105945 55515;105675 55537;104805 54780 1;104303 54345;103898 54218;103635 53610 1;103440 53190;103643 52478;104115 52440;102262 52545 1;102593 52515;102803 52537;102945 52605 33;103080 52665;103163 52762;103230 52883 33;103290 53010;103343 53160;103425 53332 33;103493 53475;103583 53633;103725 53798;69195 48825 1;69270 48660;69338 48473;69398 48248 1;69428 48113;69330 48023;69195 47955;69203 48818;69195 48825 18;124455 64207 1;123540 64485;122693 64688;121455 64710 1;119295 64755;117623 64643;116385 62880 1;115575 61740;115500 60945;115335 59550 1;114975 56640;118995 53700;122415 53370 1;123135 53295;123840 53325;124500 53430;109485 57600 1;109178 57173;108878 56655;108488 56475 1;107685 56115;106740 55845;105465 55380;113595 48600 1;113415 48825;112830 49245;112688 49433 1;112245 50010;112110 50400;112035 51248 1;111945 52110;111870 52650;112193 53370;113535 53213 1;112935 53273;112530 53220;112125 53295 1;111773 53363;111525 53528;111180 53603 1;110790 53685;110265 53655;109725 53610 1;109380 53588;109305 53512;109065 53730 1;108885 53895;108712 54030;108593 54158 1;108240 54540;107730 54405;106350 55680;112860 49238;115005 49260;95835 51690;91545 52650 1;90788 51840;90375 51375;89355 50940 1;88275 50490;87818 50070;86715 49680 1;86355 49560;86137 49650;85785 49530 1;84315 49058;84105 48900;82575 48750 1;82200 48720;81840 48983;81735 49290;77385 55830 1;77273 57983;77273 59063;77085 61200 1;77033 61733;76988 62003;77085 62520 1;77183 63052;77100 63435;77498 63795 1;78203 64463;78525 64838;79313 65415 1;80115 66015;80550 66330;81518 66585 1;82148 66758;82365 66795;83010 66623 1;83512 66495;83798 66578;84390 66615 1;85095 66668;85350 66225;85808 65580 1;86213 64995;86475 64710;86768 64035 1;87008 63473;87008 63090;87233 62588;74887 58373 1;75143 58927;75308 59235;75285 59835 1;75255 60503;75323 60840;75255 61492 1;75165 62318;75668 62707;75593 63525 1;75555 63893;75420 64073;75480 64425 1;75510 64650;75563 64845;75780 64898 1;76185 64898;76530 64665;76568 64290 1;76613 63832;76718 63525;77137 63330;78533 64695 1;78945 64065;79117 63630;79793 63270 1;80753 62760;81278 62550;82102 61830 1;82583 61410;82673 61058;82988 60495 1;83227 60060;83581 59405;83792 59083;83483 59820 1;83678 59985;83602 60262;83843 60360 1;84270 60548;84510 60660;84983 60615 1;85223 60593;85418 60555;85523 60330 1;85643 60060;85710 59918;85867 59655;85605 59430 33;85102 59137;84698 58830;84203 58463 32;84165 58665 33;83858 59010;83663 59295;83475 59603 32;83483 59820 18;86408 64755 1;86588 65775;86723 66270;86873 67290 1;86933 67740;86940 68025;86723 68415 1;86348 69075;85973 69413;86078 70155;86648 70290 1;86663 70050;86622 68946;86599 68758;109455 41640 1;108285 41723;107408 41730;106253 41693 1;105323 41670;104887 41573;103995 41760 1;103193 41933;102758 42060;101955 41910 1;99480 41468;98205 41138;95843 40290;95798 40305 1;96210 40185;96983 40110;96765 39510 1;96248 38115;95820 37373;95925 35880 1;95970 35145;96038 34575;96128 34020;115028 34088 1;115448 34245;115890 34418;116415 34650 1;116790 34823;117023 34823;117375 35040 1;117758 35295;118140 35445;118395 35820 1;118740 36345;118943 36848;118905 37283;109373 40613 1;107348 40545;106343 40582;104333 40582 1;102345 40582;101363 40418;99398 40185;96878 39855;114840 40207 1;114675 39143;114255 37838;114825 36930 1;115403 36008;115643 35573;116385 34770;80025 43350;78458 42855;81231 42023;79148 39570;75518 39030 1;76680 39015;77258 39015;78428 39015 1;78900 39015;79088 39098;79492 39360 1;80137 39810;80685 40170;81105 40628 1;82073 41640;82673 42128;83992 42585 1;84788 42870;85185 43103;85815 43673 1;86198 44025;86490 44078;86985 44235 1;87413 44385;87623 44483;88073 44588 1;88508 44700;88748 44693;89205 44670 1;90120 44640;90578 44570;91500 44622 1;94053 44791;94018 44802;97910 45470 1;99009 45659;99116 45737;100278 45985 1;100496 46037;101150 46127;101578 46202;69870 41093;74992 49965 1;75248 49643;75420 49537;75653 49185 1;75803 48953;75495 48623;75262 48465 1;74955 48278;74625 48045;74378 48300 1;74003 48698;73845 48923;73463 49305 1;73365 49403;73680 49530;73762 49425 1;73973 49140;74018 48818;74378 48765 1;74528 48750;74760 48832;74708 48975 1;74573 49328;74625 49552;74453 49875;74992 49965 18;74933 49920;74753 50310 33;75225 50520;75690 50745;76223 51098 32;76523 51090 1;76658 50985;76665 50873;76748 50715 1;76815 50573;76635 50423;76477 50400 1;76260 50378;76148 50430;75938 50400 1;75795 50385;75735 50213;75803 50085 1;76020 49673;76380 49508;76852 49545 1;77265 49590;77528 49628;77828 49920 1;77955 50055;78188 50213;78278 50040 1;78352 49890;78563 49980;78637 50137 1;78735 50363;78720 50528;78930 50655 1;79283 50880;79785 50768;80205 50753 1;80400 50753;80708 50558;80648 50363 1;80550 50078;80078 49957;79823 49785 1;79718 49725;79710 49485;79838 49485 1;79995 49485;80123 49552;80227 49425 1;80483 49103;80468 48848;80693 48495 1;80768 48375;80843 48218;80723 48135 1;80558 48037;80355 47910;80242 48060 1;80123 48218;80063 48285;79958 48435 1;79860 48578;79680 48630;79553 48525 1;78968 48075;78623 47925;77992 47550 1;77738 47408;77475 47280;77273 47475 1;77108 47640;77063 47753;76943 47940 1;76793 48173;76545 48105;76373 48300 1;75810 48930;75533 49253;74977 49875;74933 49920 18;78803 49290 1;78720 49358;78660 49350;78570 49380 1;78480 49418;78413 49343;78383 49253 1;78323 49103;78405 49012;78488 48863 1;78585 48668;78727 48623;78930 48533 1;79028 48495;79133 48615;79133 48720 1;79125 48998;78975 49117;78788 49313;78803 49290 18;69158 66180 1;69248 66180;69315 66165;69428 66150 1;69570 66143;69623 66023;69683 65880 1;69773 65655;69825 65393;70073 65400 1;70253 65408;70350 65393;70538 65370 1;70710 65355;70703 65145;70733 64965 1;70762 64748;70793 64635;70838 64410 1;70852 64305;70838 64192;70733 64155 1;70583 64117;70710 63930;70718 63780 1;70725 63608;70740 63525;70748 63345 1;70748 63188;70950 63052;70823 62955;70568 63015 33;70433 63165;70283 63315;70125 63480 1;69975 63637;70320 64200;70193 64350 1;70050 64508;69413 64328;69308 64492 1;69248 64582;69195 64673;69143 64762;69150 66188;69158 66180 18;70485 59445;70710 60015;93188 51375;81518 41640 1;81435 41843;81390 42113;81188 42060 1;80865 41993;80498 41850;80378 42150 1;80137 42713;79755 42855;79523 43410 1;79425 43635;79238 43793;79387 43980 1;79500 44138;79620 44273;79733 44430 1;79808 44550;79800 44678;79718 44790 1;79613 44940;79496 45231;79645 45328 1;79781 45426;79688 45503;79838 45585 1;79913 45638;80085 45390;80137 45300 1;80175 45218;80227 45128;80333 45135 1;80640 45180;80805 45240;81113 45165 1;81443 45090;81608 45015;81953 44985 1;82102 44978;82298 45135;82223 45270 1;82102 45480;82012 45593;82028 45825 1;82028 46005;82110 46103;82253 46200 1;82387 46305;82500 46320;82673 46275 1;82755 46260;82808 46245;82898 46260 1;83010 46290;83078 46388;83078 46500 1;83070 46635;83085 46733;83198 46800 1;83303 46875;83348 46980;83483 46965 1;83678 46950;84345 47213;84473 47063 1;84600 46912;84570 46703;84570 46500 1;84570 46305;83963 46073;83798 45960 1;83708 45908;83633 45908;83543 45945 1;83415 45998;83325 46050;83213 45990 1;83003 45893;82883 45773;82852 45540 1;82823 45345;82785 45218;82898 45045 1;82995 44895;83130 44850;83318 44865 1;83610 44895;83805 45015;84053 44850 1;84248 44723;84450 44655;84458 44415 1;84458 44183;84315 44078;84143 43920 1;83648 43500;83348 43373;82838 42975 1;82545 42758;82448 42585;82268 42270 1;82065 41925;81930 41707;81518 41640 18;90218 53325 1;90188 53130;90083 53018;90038 52823 1;90008 52710;90045 52515;90023 52395 1;89977 52200;89805 52133;89573 51930 1;89063 51495;88733 50985;88313 50460;69180 54270;69203 54233 1;69233 54150;69218 54075;69180 54000;69188 54262;69180 54270 18;69180 52860 1;69240 52785;69293 52703;69338 52582 1;69495 52080;69518 51810;69637 51293 1;69653 51233;69563 51203;69503 51188 1;69390 51165;69285 51158;69188 51158;69188 52867;69180 52860 18;69188 53783 1;69278 53768;69345 53723;69360 53655 1;69383 53573;69308 53483;69180 53423;69188 53783 18;69218 48938 1;69668 48773;69893 48683;70358 48518 1;70403 48503;70283 48480;70238 48457 1;69983 48353;69795 48398;69608 48203;69218 48938 18;74640 51518 1;74475 51690;74453 51923;74580 52043 1;74700 52155;74933 52117;75090 51938 33;75255 51773;75278 51540;75158 51427 1;75030 51308;74798 51345;74640 51518 18;71977 51068 1;71835 51150;71775 51203;71678 51323 1;71558 51473;71423 51540;71242 51503 1;71093 51473;71018 51420;70867 51427 1;70658 51443;70477 51570;70477 51773 1;70455 52373;70425 52665;70433 53258 1;70433 53408;70485 53543;70628 53558 1;70740 53573;70808 53617;70928 53588 1;71070 53558;71145 53468;71198 53318 1;71400 52740;71400 52418;71678 51863 1;71715 51787;71805 51787;71887 51818 1;72075 51893;72165 51953;72367 51998 1;72428 52020;72495 52028;72555 52012 33;72600 51998;72645 51968;72683 51908 1;72735 51810;72765 51758;72818 51653 1;72848 51593;72855 51518;72833 51457 33;72825 51420;72795 51383;72758 51353 1;72548 51240;72443 51195;72233 51082 1;72113 51030;72008 50940;71933 51023;72098 49343 1;71963 49425;71925 49508;71798 49582 1;71678 49658;71678 49883;71813 49927 1;72038 50018;72173 50040;72428 50018 1;72623 50003;72727 50010;72923 50048 1;73035 50078;73230 49995;73268 49883;72098 49343 18;72098 51908 32;71992 51870 33;71963 51855;71925 51840;71887 51818 1;71805 51787;71715 51787;71678 51863 1;71400 52418;71400 52740;71198 53318 1;71160 53408;71123 53475;71070 53528 32;71183 53558 33;71370 53543;71550 53520;71558 53332 1;71558 53265;71588 53228;71588 53153 1;71588 53040;71490 53003;71498 52883 1;71505 52770;71565 52688;71678 52643 1;71850 52575;71963 52500;72008 52313 1;72030 52177;72068 52110;72098 51983;72098 51908 50;70823 48802 32;70770 48908 33;70200 50115;69983 50858;69788 52207 1;69720 52650;69600 52927;69803 53318 1;69998 53715;70185 53887;70553 54128 32;71783 54188 32;71820 54075 33;72128 53280;72233 52830;72578 52012 32;72510 52020 33;72465 52028;72413 52020;72367 51998 1;72255 51975;72180 51953;72105 51915 32;72090 52012 33;72060 52125;72030 52193;72008 52313 1;71963 52500;71850 52575;71678 52643 1;71565 52688;71505 52770;71498 52883 1;71490 53003;71588 53040;71588 53153 1;71588 53228;71558 53265;71558 53332 1;71550 53550;71303 53543;71093 53565 32;70890 53595 33;70793 53610;70725 53573;70628 53558 1;70485 53543;70433 53408;70433 53258 1;70425 52665;70455 52373;70477 51773 32;70515 51623 33;70575 51510;70710 51443;70867 51427 1;70935 51427;70988 51435;71040 51450 32;71242 51503 33;71423 51540;71558 51473;71678 51323 1;71700 51293;71723 51262;71753 51240 32;71963 51037 32;71925 50887 33;71873 50745;71775 50640;71633 50512 1;71580 50483;71498 50528;71498 50588 1;71490 50685;71498 50738;71498 50828 1;71498 50903;71430 50963;71363 50948 1;71145 50918;71033 50903;70823 50858 1;70740 50843;70688 50768;70718 50693 1;70755 50580;70725 50512;70748 50393 1;70755 50348;70800 50318;70852 50318 1;70935 50325;70973 50340;71063 50348 1;71145 50363;71190 50250;71168 50168 1;71108 49988;71048 49898;71033 49703 1;70995 49410;71048 49253;71183 48983;70823 48802 50;70440 52448 33;70433 52695;70425 52935;70433 53258 1;70433 53408;70485 53543;70628 53558 1;70740 53573;70808 53617;70928 53588 1;71070 53558;71160 53468;71213 53318 1;71325 52995;71385 52762;71453 52508 32;71475 52380 1;71063 52313;70838 52298;70433 52223;70440 52448 50;69158 60825 1;69428 60720;69713 60660;70088 60675 1;70650 60713;70980 60765;71445 61095 1;71948 61463;72180 61853;72165 62475 1;72150 63105;72270 63443;72570 63990 1;72915 64680;73050 65085;73568 65655 1;74040 66180;74325 66405;74828 66915 1;75180 67283;75450 67492;75968 67492 1;76575 67500;76898 67523;77490 67695 1;78015 67860;78435 67703;78810 68115 1;78990 68325;79117 68385;79365 68490 1;79785 68693;80025 68760;80408 69053 1;80738 69323;80985 69413;81165 69795 1;81375 70283;81637 70643;82170 70650 1;82650 70665;82898 70343;83130 69915 1;83288 69623;83475 69540;83625 69233 1;83768 68925;84038 68790;84390 68813 1;84990 68865;85245 69180;85688 69615 1;86227 70155;86438 70492;87045 70950 1;87600 71385;87810 71865;88508 71933 1;88875 71970;89078 71850;89408 71655 1;89887 71363;89820 70913;90165 70455 1;90525 69983;90750 69765;91245 69413 1;91838 69000;92130 68700;92850 68550 1;93428 68445;93727 68400;94328 68430 1;95145 68483;95535 68670;96368 68693 1;96705 68715;96870 68490;97087 68213 1;97808 67290;97815 66615;98310 65535 1;98558 64973;99060 64815;99690 64815 1;100245 64815;100598 64973;100988 65393 1;101745 66240;102105 66690;102810 67590 1;103200 68115;103440 68363;103988 68715 1;104550 69083;104887 69330;105570 69315 1;105990 69315;106238 69375;106628 69173 1;107137 68925;107355 68693;107887 68453 1;108525 68160;108915 68063;109628 68093 1;110475 68145;110940 68295;111645 68775 1;112395 69300;112860 69443;113565 70035 1;113925 70350;114255 70335;114750 70290 1;115425 70245;115920 70223;116370 69690 1;116790 69195;116850 68790;116925 68130 1;117000 67500;117255 67245;117488 66630 1;117705 66045;117780 65715;117825 65070 1;117840 64883;117855 64793;117870 64590 1;117900 62715;116137 62302;114630 61170 1;113528 60360;112958 59963;111765 59295 1;110460 58575;109860 58125;108608 57293 1;107768 56753;107340 56512;106508 55950 1;105870 55545;105660 55140;104970 54855 1;103785 54375;103260 53992;102090 53490 1;101115 53093;100538 53070;99645 52515 1;98887 52043;98595 51683;97845 51195 1;96975 50640;96600 50153;95588 49950 1;95220 49890;95070 49733;94725 49575 1;93727 49133;93548 48420;92625 47835 1;91995 47445;91620 47325;91088 46815 1;90465 46245;90308 45705;89528 45412 1;89153 45285;88988 45218;88710 45098;69173 58680;69758 58988 1;69930 58950;70020 58927;70200 58875 1;70320 58845;70418 58883;70508 58965;70867 58455 1;70852 58433;70852 58395;70852 58358 1;70838 57983;70838 57795;70808 57420 1;70793 57338;70695 57338;70628 57285 1;70515 57188;70455 57143;70320 57150 1;70193 57165;70163 57105;70065 57113 1;69998 57113;69938 57120;69900 57165 1;69780 57308;69698 57360;69578 57488 1;69383 57698;69262 57885;69165 58073;69173 58680 18;69158 59453 1;69352 59325;69548 59220;69742 59137 1;69893 59078;69848 58568;70200 58523 1;70575 58478;70725 58860;70935 58957 1;71220 59093;71438 59100;71693 59130 1;71850 59153;72068 58860;72300 58905 1;72623 58980;72735 59348;72960 59475 1;73102 59550;73268 59685;73455 59783 1;73913 60052;74055 60285;74018 60802 1;73943 61508;73590 61613;73538 62302 1;73500 62753;73605 62985;73778 63383 1;74010 63953;73875 64380;74295 64823 1;75045 65633;75510 66300;76620 66300 1;77775 66300;78705 66180;79418 67102 1;79748 67545;80168 67463;80580 67823 1;80955 68175;81345 68175;81578 68625 1;81727 68933;81908 69120;82260 69143 1;82568 69165;82650 68865;82815 68580 1;83258 67845;83700 67320;84578 67305 1;85290 67305;85575 67673;86220 67980 1;87165 68460;87660 68895;88740 68903 1;89617 68925;90188 68880;90855 68303 1;91680 67590;92160 66983;93255 66983 1;94065 66983;94477 66945;95295 66983 1;96488 67043;97260 66300;97695 65183 1;98085 64185;98730 63555;99818 63503 1;100770 63473;101318 63735;102060 64343 1;102345 64598;102495 64815;102667 65063;70867 58455;70508 58965 1;70538 58988;70560 59010;70590 59033 1;70733 59198;70935 59115;71130 59010 1;71258 58943;71333 58740;71318 58590 1;71295 58470;71085 58410;70965 58425 1;70920 58440;70875 58492;70867 58455 18;69173 59348;69270 59468 1;69420 59250;69488 59048;69758 58988;69165 58680;69173 59348 18;69150 64508;69158 64500 32;69150 64508 18;69165 61440 1;69240 61403;69233 61290;69233 61185 1;69210 61005;69180 60855;69158 60720;69165 61448;69165 61440 18;69158 59595 1;69195 59558;69233 59520;69270 59468;69165 59340;69165 59603;69158 59595 18;69165 61440 1;69240 61403;69233 61290;69233 61185 1;69210 61005;69180 60855;69158 60720;75105 54075 1;74992 54405;74887 54555;74843 54893 1;74828 54990;74858 55110;74955 55095 1;75075 55088;75300 55110;75390 55050 1;75465 55005;75450 54878;75480 54765 1;75548 54450;75525 54293;75600 53970;75105 54075 18;74813 55433 1;74813 55582;74880 55688;75023 55740 1;75173 55800;75262 55800;75405 55883 1;75540 55980;75645 56033;75683 56190 1;75698 56287;75742 56370;75848 56370 1;75960 56370;75968 56242;76028 56137 1;76080 56033;76133 55988;76230 55898 1;76328 55808;76305 55710;76320 55575 1;76320 55508;76223 55500;76155 55492 1;75645 55455;75398 55373;74895 55410;74813 55433 18;76283 55523 1;76403 55170;76553 55035;76770 54720 1;76770 54510;76440 54728;76253 54810 1;75930 54953;75810 55140;75683 55455;76283 55523 18;77295 53948 1;77100 54218;76995 54345;76845 54630;76733 54765 1;76545 55043;76403 55185;76298 55478;76313 55643 1;76305 55748;76305 55823;76230 55898 1;76133 55988;76080 56033;76028 56137 1;75968 56242;75960 56370;75848 56370 1;75742 56370;75698 56287;75683 56190 1;75645 56033;75540 55980;75405 55883 1;75315 55838;75248 55815;75180 55800;74918 55688 1;74843 55635;74813 55568;74813 55470;74835 54945 1;74835 54930;74835 54915;74843 54893 1;74880 54593;74970 54443;75068 54180 32;76898 54525;76770 54720 33;76620 54938;76508 55065;76410 55238 32;76448 55305 1;76673 55305;76793 55328;77010 55403 1;77070 55433;77130 55463;77183 55410 1;77453 55148;77640 55058;77865 54750 1;77895 54713;77963 54705;77955 54645 1;77865 54278;77588 54188;77273 53985;76898 54525 18;69195 47310 1;69270 47280;69262 47160;69203 47123;69210 47295;69195 47310 18;69203 46635 1;69233 46688;69262 46748;69293 46815 1;69315 46890;69323 46928;69367 46995 1;69405 47070;69450 47115;69533 47100 1;69735 47078;69840 47040;70058 47033;70433 46463;70125 46313;69458 45818;69203 45570;69210 46643;69203 46635 18;69765 44475 1;69818 44130;69840 43943;70005 43620;70020 43530 33;70012 43463;69945 43410;69878 43425 1;69788 43455;69735 43440;69653 43463 1;69570 43493;69585 43568;69540 43628 1;69405 43815;69338 43928;69323 44152 1;69308 44303;69293 44378;69300 44520 32;69323 44595 1;69352 44610;69360 44640;69398 44633;69765 44475 18;69810 44460 1;69908 44415;70005 44385;70140 44310 1;70185 44287;70193 44228;70178 44168 1;70110 43965;70050 43845;70028 43658 32;70020 43530 32;69990 43470 32;69788 44025 32;69735 44483;69810 44460 18;69218 43140;69285 43103;69233 43050 32;69225 43133;69218 43140 18;69203 45593 1;69495 45923;69870 46170;70335 46418 32;70425 46448 1;70500 46305;70553 46230;70635 46080 1;70515 45983;70455 45930;70328 45840 1;70275 45810;70283 45743;70320 45683 1;70358 45630;70373 45600;70418 45540 1;70470 45473;70425 45375;70350 45323 1;70178 45225;70110 45150;69968 45015 1;69818 44888;69788 44753;69780 44550;69765 44475 32;69398 44633 1;69360 44640;69352 44610;69323 44595;69300 44520 33;69293 44378;69308 44303;69323 44152 1;69323 44100;69330 44055;69338 44018 32;69345 43935 1;69293 43957;69248 43980;69210 44003;69210 45600;69203 45593 18;69600 43448;69218 43073;70935 43680 1;70958 43763;71025 43800;71108 43785 1;71183 43777;71220 43710;71227 43628 1;71242 43313;71250 43155;71295 42840 1;71303 42765;71318 42713;71280 42645 1;71198 42525;71123 42495;71018 42398 1;70965 42360;70883 42435;70883 42495 1;70875 42623;70838 42713;70733 42765 1;70620 42825;70545 42818;70455 42893 1;70395 42945;70448 43027;70515 43058 1;70643 43125;70748 43133;70815 43253 1;70890 43410;70860 43515;70943 43673;70935 43680 18;72150 40838;72968 40718;72473 39323;73290 39412;70755 38490 1;70710 38655;70703 38738;70680 38902 1;70665 38985;70710 39060;70793 39068 1;70852 39082;70890 39082;70958 39082 1;71040 39082;71115 39143;71130 39225 1;71137 39360;71115 39435;71123 39563 1;71123 39683;71108 39758;71168 39855 1;71265 40035;71295 40170;71483 40253 1;71558 40290;71640 40283;71640 40193 1;71633 39990;71498 39878;71468 39668 1;71438 39495;71505 39390;71625 39248 1;71678 39180;71760 39188;71850 39203 1;71992 39240;72075 39218;72218 39277 1;72367 39353;72435 39457;72458 39623 1;72495 39945;72495 40110;72473 40425 1;72465 40523;72555 40628;72645 40590 1;72765 40537;72825 40500;72945 40433 1;73020 40395;73065 40350;73080 40260 1;73155 39660;73245 39360;73313 38753;70755 38490 18;71715 42308 1;71708 42338;71715 42368;71745 42368 1;71873 42405;71933 42450;72075 42473 1;72150 42488;72188 42495;72248 42435 1;72398 42293;72428 42203;72623 42105 1;72727 42053;72750 41970;72795 41850 1;72840 41715;72878 41640;72780 41527 1;72713 41468;72645 41453;72563 41468 1;72345 41520;72240 41543;72038 41603 1;71910 41648;71850 41723;71828 41843 1;71783 42030;71753 42128;71715 42308 18;71887 40973 1;71940 40890;71828 40845;71775 40770 1;71655 40628;71648 40440;71625 40253;71588 40260 33;71550 40275;71512 40275;71483 40253 1;71295 40170;71265 40035;71168 39855 1;71108 39758;71123 39683;71123 39563 1;71115 39435;71137 39360;71130 39225 1;71115 39143;71040 39082;70958 39082 1;70890 39082;70852 39082;70793 39068 1;70762 39068;70740 39060;70725 39045 32;70680 39015 1;70538 39240;70477 39360;70380 39593 1;70328 39720;70305 39803;70350 39923 1;70500 40350;70613 40553;70860 40935 1;70905 41010;70980 41018;71063 40995 1;71393 40920;71565 40965;71910 40988;71887 40973 18;71895 40912;72473 40515 32;72473 40425 33;72495 40110;72495 39945;72458 39623 1;72435 39457;72367 39353;72218 39277 1;72075 39218;71992 39240;71850 39203 1;71760 39188;71678 39180;71625 39248 1;71505 39390;71438 39495;71468 39668 1;71498 39878;71633 39990;71640 40193 1;71640 40223;71625 40245;71617 40260 32;71625 40320 33;71648 40485;71663 40650;71775 40770 1;71798 40808;71828 40830;71858 40860;71895 40912 18;74992 41880 1;74835 41978;74738 42037;74663 42195 1;74588 42353;74610 42480;74715 42615 1;74873 42840;75150 42660;75390 42525;74992 41880 18;74693 38873 1;74925 38963;75008 39090;75210 39240 1;75323 39330;75413 39383;75555 39345 1;75653 39330;75660 39180;75600 39098 1;75533 39015;75510 38955;75503 38843;74693 38873 18;75540 40043 1;76695 40020;77280 39975;78443 40088 1;78653 40110;78750 40140;78968 40155 1;79102 40170;79148 40245;79275 40298 1;79665 40478;80438 41018;80820 41213;75578 41010 1;75503 41100;75465 41152;75398 41235 1;75338 41310;75293 41430;75383 41468 1;75450 41513;75480 41543;75563 41565 1;75645 41603;75705 41588;75795 41550 1;76012 41468;76117 41400;76335 41287 1;76425 41243;76500 41265;76590 41310 1;76800 41430;76905 41483;77130 41580 1;77198 41618;77265 41595;77333 41535 1;77490 41393;77558 41310;77730 41168 1;77835 41078;77933 41108;78075 41078 1;78308 41040;78383 40830;78420 40590 1;78443 40433;78435 40350;78450 40178 1;78450 40118;78383 40080;78323 40073 1;78030 40073;77887 40050;77602 40050 1;77355 40050;77227 40027;76988 40035 1;76905 40043;76830 40103;76852 40178 1;76883 40313;76905 40380;76898 40515 1;76883 40658;76867 40800;76740 40815 1;76380 40875;76200 40860;75848 40912 1;75727 40935;75637 40912;75570 40995;75578 41010 18;75653 40433 1;75863 40448;75975 40448;76193 40448 1;76305 40448;76387 40402;76448 40298 1;76523 40162;76575 40095;76650 39945 1;76680 39878;76620 39810;76560 39758 1;76485 39705;76410 39675;76335 39713 1;76095 39832;75975 39893;75720 39945 1;75615 39968;75540 40005;75518 40103 1;75495 40193;75480 40238;75473 40328 1;75458 40402;75548 40440;75623 40433;75653 40433 18;80940 48060 1;81038 47895;81150 47858;81255 47693 1;81398 47468;81383 47295;81390 47018 1;81390 46748;81367 46553;81165 46380 1;80955 46215;80775 46110;80535 46200 1;80265 46313;80168 46448;79980 46658 1;79883 46770;79883 46995;80033 47018 1;80205 47055;80295 47003;80475 46980 1;80588 46973;80745 47063;80700 47168 1;80580 47430;80573 47580;80445 47835;80940 48060 18;78788 49313 1;78975 49117;79125 48998;79133 48720 1;79133 48615;79028 48495;78930 48533 1;78727 48623;78585 48668;78488 48863 1;78405 49012;78323 49103;78383 49253 1;78413 49343;78480 49418;78570 49380 1;78660 49350;78720 49358;78803 49290;78788 49313 18;80835 52140 1;81015 52223;81098 52305;81300 52343 1;81390 52365;81480 52343;81525 52253 1;81585 52117;81555 51975;81435 51885 1;81308 51802;81248 51750;81120 51668;80835 52140 18;82253 53228 1;82463 53310;82680 53265;82740 53108 1;82800 52965;82680 52770;82470 52680 33;82268 52598;82043 52658;81990 52800 1;81923 52950;82050 53145;82253 53228 18;84458 54353 1;84608 54420;84690 54427;84855 54473 1;84975 54518;85035 54548;85163 54585 1;85598 54720;85838 54735;86295 54795 1;86318 54802;86363 54818;86363 54787 1;86288 54495;86145 54383;86055 54082 1;86033 54023;85935 54068;85890 54105 1;85748 54225;85673 54285;85515 54375 1;85440 54420;85387 54435;85313 54412 1;85110 54367;84990 54383;84810 54285 1;84645 54203;84653 54037;84488 53970 1;84293 53903;84173 54045;84023 54173;84458 54353 18;88260 54473 1;88575 54367;88703 54248;89003 54090 1;89033 54075;89070 54015;89040 54008 1;88905 54000;88838 53970;88718 54008 1;88658 54030;88590 54090;88568 54030 1;88523 53955;88515 53910;88485 53820 1;88440 53730;88305 53783;88238 53850 1;87998 54098;87983 54308;87870 54623;88260 54473 18;82643 48832 1;82425 49073;82178 49140;82148 49455 1;82117 49688;82117 49875;81915 49973 1;81810 50025;81727 49965;81645 50033 1;81615 50055;81608 50070;81600 50100 1;81548 50250;81518 50325;81503 50475 1;81488 50543;81398 50715;81458 50745 1;81578 50820;81698 50768;81848 50783 1;82178 50828;82328 50865;82635 51015 1;82793 51105;82958 51300;83115 51398 1;83168 51443;83280 51210;83325 51150 1;83393 51068;83460 50970;83565 51008 1;83760 51082;83865 51143;83992 51308 1;84105 51465;84195 51525;84367 51608 1;84615 51742;84773 51742;85058 51795 1;85553 51893;85793 51945;86295 52035 1;87083 52193;87473 52320;88238 52568 1;88448 52643;88620 52755;88628 52973 1;88628 53078;88613 53175;88710 53213 1;88852 53287;88943 53213;89108 53205 1;89280 53205;89385 53078;89550 53145 1;89738 53235;89850 53258;90008 53393;90510 53123;91395 52680;90578 51810;90270 51563;89798 51210;89258 51000;88860 50820;87750 50250;87435 50100;86700 49778;86363 49710;85920 49665;84825 49305;84352 49177;83617 48998;82643 48832 18;88860 52350 1;88635 52238;88583 52005;88650 51758 1;88680 51637;88823 51637;88950 51660 1;89265 51728;89393 51870;89633 52088 1;89745 52200;89738 52365;89640 52478 1;89453 52703;89160 52552;88920 52395;88860 52350 18;88920 52395 1;89160 52552;89453 52703;89640 52478 1;89738 52365;89745 52200;89633 52088 1;89393 51870;89265 51728;88950 51660 1;88823 51637;88680 51637;88650 51758 1;88583 52005;88635 52238;88920 52395 18;81293 54188 1;81143 53963;81045 53820;80798 53723 1;80693 53685;80580 53700;80535 53798 1;80468 53925;80445 54068;80565 54150 1;80783 54323;80910 54383;81150 54525 1;81210 54570;81338 54578;81338 54495 1;81338 54345;81367 54225;81255 54128;81293 54188 18;81203 54713;82095 54735;81180 56423 33;81218 56378;81270 56332;81323 56280 32;81390 56205 1;81173 55950;81083 55718;80918 55425 1;80880 55380;80805 55410;80753 55425 1;80633 55470;80565 55552;80617 55658 1;80753 55988;80918 56175;81135 56453;81180 56423 50;81367 56242 1;81083 56505;80940 56730;80783 57075 1;80723 57203;80948 57203;81083 57188 1;81413 57165;81563 57023;81840 56835;81367 56242 18;81608 57008 1;81795 57255;81915 57412;81938 57713 1;81945 57915;81908 58058;82073 58162 1;82268 58305;82380 58365;82620 58418 1;82943 58500;83130 58470;83430 58628 1;83512 58680;83588 58770;83535 58845 1;83453 58950;83430 59018;83325 59078 1;83288 59108;83333 59160;83378 59175 1;83453 59213;83490 59258;83580 59273 1;83925 59340;83933 58883;84150 58590 1;84165 58568;84098 58590;84083 58568 1;83955 58463;83887 58410;83753 58320 1;82935 57818;82553 57503;81863 56835;81795 56865 33;81735 56910;81683 56948;81630 56985 32;81608 57008 18;79560 57285;80573 57308 1;80303 57600;80115 57885;80160 58275;107977 61328;109290 59745 32;109778 56753 32;111743 56580 32;111345 53918 32;113438 53565 32;115530 48675 32;118710 48150;118643 47520 32;119880 47445;121268 47355 32;95288 77985;95070 77535;94470 77835 32;94538 77985;95288 77985 18;96922 77460;96352 75968 32;95693 76223 32;95565 75900 32;94553 76298 32;94890 77175 32;95798 76830 32;96150 77760 32;96922 77460 18;102600 78008;102600 77453 32;101512 77453;101512 78008;102600 78008 18;103118 76590;102930 77602 32;104265 77835 32;104453 76830 32;103118 76590 18;124433 72585;122693 69503 32;122078 69855 32;121935 69608 32;121073 70102 32;123158 73793 32;122880 73958 32;123480 75023 32;124433 74490;124440 72585;124433 72585 18;124440 69053;124297 69143 32;124208 69000 32;123833 69240 32;124448 70208;124448 69053;124440 69053 18;124455 65903;124005 66300 32;124455 66818;124462 65903;124455 65903 18;119250 65843;119258 66113 32;118950 66120 32;119003 67515 32;119573 67485 32;119550 66637 32;120488 66600 32;120488 66405 32;120870 66390 32;120900 66983 32;121590 66953 32;121575 66173 32;121080 66188 32;121058 65235 32;120383 65250 32;120405 65805 32;119250 65843 18;114968 65355;116408 65280 32;116430 65843 32;117210 65813 32;117158 64995 32;116768 65025 32;116700 63945 32;116070 63990 32;116070 64155 32;115665 64177 32;115680 64537 32;114698 64598 32;114705 64883 32;114330 64912 32;114413 66608 32;115028 66578 32;114968 65355 18;113137 65588;113085 66248 32;113542 66278 32;113565 66030 32;113783 66038 32;113820 65640 32;113137 65588 18;114848 69855;115837 69293 32;116325 69668 32;116250 70065 32;116933 70215 32;117075 69593 32;116933 69555 32;117120 68685 32;116483 68565 32;116430 68887 32;115462 68625 32;115283 68213 32;114518 68670 32;114683 69053 32;114518 69150;114848 69855 18;124493 54315;123960 54375 32;123983 54495 32;123120 54600;123255 55733 32;124140 55620 32;124118 55350 32;124493 55305;124500 54315;124493 54315 18;120195 53985;120712 58133 32;121178 58088;120660 58148;121012 58110;120945 57510 32;120578 57540;120885 54488;120945 54945 32;121080 54915 32;121193 55680 32;121672 55605 32;121628 55223 32;121905 55170 32;121935 55373 32;122520 55283 32;122408 54398 32;121635 54503 32;121628 54383 32;120885 54488 18;119970 55710;118658 55875 32;118635 55710 32;118012 55785 32;118102 56528 32;118268 56512 32;118403 57585 32;119400 57457 32;119265 56408 32;120038 56310 32;119970 55710 18;119917 59033;119955 59430 32;119265 59505 32;119363 60315 32;120090 60225 32;120060 59850 32;120998 59738 32;120915 58920 32;119917 59033 18;116977 59768;118170 59558 32;118028 58770 32;117533 58867 32;117488 58658 32;116422 58853 32;116535 59535 32;115973 59640 32;116093 60375 32;117053 60218 32;116977 59768 18;117195 62955;117068 63120 32;117368 63353;117727 62895;118268 62805;118073 61515 32;118425 61470 32;118335 60893 32;118028 60945 32;117968 60570 32;117233 60690 32;117292 61088 32;117180 61117 32;117233 61448 32;116977 61492 32;117195 62955 18;122400 63923;123428 63795 32;123300 62760 32;124313 62617 32;124208 61800 32;122760 61980 32;122813 62408 32;122212 62475 32;122400 63923 18;124470 59617;122917 59820;123075 61088 32;123938 60968 32;123893 60518 32;124477 60443;124477 59617;124470 59617 18;121568 59512;124485 59160;124485 56677;121178 57105;69135 68858 1;71648 70628;73065 71580;75713 73440 1;77543 74738;78413 75458;80175 76845 1;80723 77288;81060 77535;81510 77940;82133 77948;82193 77685;79598 75593;74040 71685;69135 68370;69135 68873;69135 68858 18;82410 77948;82260 77685 32;82140 77948;82410 77948 18;81503 77933 1;81060 77535;80723 77288;80175 76845 1;78413 75458;77543 74738;75713 73440 1;73058 71580;71648 70628;69128 68850;69128 72615;69352 74865;73883 77925;81503 77940;81503 77933 18;120083 39735;120938 39900 32;121118 38902 32;120270 38738 32;120083 39735 18;119220 43928;115898 44108 32;112658 44033 32;109500 43140 32;109493 41123 32;109485 39743 32;109485 38348 32;110948 38340 32;114120 38318 32;114450 40470 32;115852 41730 32;115852 42428;116325 42428;116325 41738;118500 40335 32;118605 37103 32;122085 38655 32;124553 37553;110438 64005;111825 64005 32;111825 64073 32;112635 64073 32;112635 63435 32;112080 63435 32;112080 63052 32;111120 63052 32;111120 63255 32;110438 63255 32;110438 64005 18;110385 60015;110415 60323 32;110078 60360 32;110137 60795 32;109733 60840 32;109808 61358 32;110422 61275 32;110385 60908 32;110685 60870 32;110715 61103 32;111623 60990 32;111495 59880 32;110385 60015 18;112837 61170;113550 61088 32;113550 61103 32;113535 60953 32;113790 60915 32;113828 61238 32;114458 61162 32;114375 60495 32;114098 60525 32;113993 59655 32;113430 59715 32;113453 59925 32;112703 60008 32;112837 61170 18;111300 59115;112208 59010 32;112005 57270 32;111098 57367 32;111300 59115 18;113648 58455;114465 58365 32;114428 58050 32;114810 57998 32;114735 57345 32;114563 57353 32;114488 56662 32;113453 56775 32;113648 58455 18;114930 58658;113153 58867 32;113190 59213 32;114915 59018 32;114615 56235;114398 54188 32;113010 54345 32;113070 54930 32;113618 54885 32;113768 56325 32;114615 56235 18;115845 55103;115928 55740 32;116573 55643 32;116498 55012 32;115845 55103 18;115792 53550;115860 54533 32;116775 54465 32;116805 54735 32;117360 54690 32;117278 53445 32;115792 53550 18;119738 51653;118508 51735 32;118523 51975 32;117983 52012 32;118050 53025 32;118890 52965 32;118875 52710 32;119797 52643 32;119738 51653 18;115628 50670;115785 51968 32;115387 52020 32;115433 52455 32;116520 52328 32;116475 52028 32;117128 51953 32;116940 50512 32;115628 50670 18;116258 50453;116955 50558 32;117053 49905 32;116355 49793 32;116258 50453 18;117265 49184;117337 50190 32;118448 50100 32;118383 49101 32;117265 49184 18;119663 51090;120413 51398 32;120345 50783 32;119850 50588 32;119663 51090 18;121275 52890;121538 52912 32;121590 52425 32;121313 52387 32;121275 52890 18;119595 49245;120863 49245 32;120863 48698 32;120443 48698 32;120443 48510 32;120593 48510 32;120593 47955 32;119310 47955 32;119310 48488 32;119715 48488 32;119715 48735 32;119595 48735 32;119595 49245 18;121748 50153;121770 51173 32;123060 51128 32;123038 50115 32;121748 50153 18;124508 50063;124050 50010;123938 51045 32;124508 51105;124515 50063;124508 50063 18;124515 46845;123540 46823;123518 47738 32;124523 47760;124523 46845;124515 46845 18;124523 46245 1;123135 46343;122685 46275;121245 46313;121272 47476;91035 50423;81653 48435;82755 46448 1;82883 45675;82545 45270;82598 44475;81203 60323;82369 75957;83640 59115 1;83333 59078;83175 59213;82883 59137 1;82545 59063;82380 59010;82050 58957 1;81495 58875;81173 58658;80910 58170 1;80790 57960;80715 57863;80633 57637 1;80565 57473;80408 57398;80227 57420 1;79852 57473;79643 57480;79313 57653 1;79155 57742;79035 57998;79193 58080 1;79620 58328;79808 58508;80273 58695 1;80655 58860;80895 58988;81090 59355 1;81240 59662;81383 59798;81690 59948 1;82163 60188;82380 60345;82860 60563;83640 59115 18;87345 62145 1;87405 61965;87503 61912;87645 61770 1;88020 61395;88283 61260;88545 60795 1;88568 60758;88560 60698;88515 60683 1;87675 60533;87248 60443;86483 60068 1;86280 59978;86168 59948;85988 59828;85800 59760 33;85688 59963;85620 60105;85523 60330 1;85418 60555;85223 60593;84983 60615 1;84840 60630;84720 60630;84608 60623 32;84398 60525 1;84173 60660;84098 60758;83850 60825 1;83543 60915;83378 60893;83063 60870 1;82973 60870;82875 60840;82852 60930 1;82845 61012;82755 61058;82808 61103 1;83010 61328;83040 61470;83115 61762 1;83183 62093;83198 62273;83115 62588 1;83085 62700;83295 62783;83378 62700 1;83625 62453;83715 62242;84053 62115 1;84615 61912;85050 62490;85215 63068 1;85260 63240;85328 63323;85477 63420 1;85905 63713;85973 64035;86183 64508 1;86205 64567;86288 64628;86325 64575 1;86460 64373;86520 64268;86625 64035 1;86655 63960;86700 63893;86655 63818 1;86588 63728;86505 63728;86415 63668 1;86250 63578;86160 63443;86190 63248 1;86213 63090;86303 63037;86393 62895 1;86483 62753;86430 62617;86340 62468 1;85943 61875;85928 61440;85965 60720 1;85965 60570;86325 60713;86318 60863 1;86265 61650;86528 62137;87120 62655;87345 62145 18;80123 63098 33;80018 63158;79913 63330;79800 63390 1;79170 63728;79058 64073;78705 64635 32;78510 64770 33;78735 64973;78983 65183;79313 65415 1;79538 65595;79740 65745;79935 65873 32;80250 65970 1;80768 65678;81098 65528;81383 64995 1;81420 64912;81323 64823;81233 64808 1;80783 64770;80550 64733;80123 64598 1;80055 64582;80055 64463;80123 64425 1;80408 64283;80528 64170;80820 64028 1;80933 63975;80985 63900;81015 63773 1;81038 63660;81038 63600;81060 63480 1;81068 63375;81083 63300;81030 63203 1;80985 63143;80918 63143;80843 63158 1;80708 63188;80655 63233;80535 63270 1;80408 63323;80325 63203;80250 63090;80123 63098 50;82163 66180 1;82530 66173;82725 66165;83085 66053 1;83205 66015;83235 65910;83258 65775 1;83310 65438;83325 65220;83565 64957 1;83693 64815;83700 64695;83843 64552 1;83910 64485;83918 64410;83887 64313 1;83843 64200;83798 64148;83775 64028 1;83753 63953;83640 63968;83580 64012 1;83378 64155;83213 64185;82988 64102 1;82883 64073;82830 64155;82755 64223 1;82455 64485;82193 64628;81810 64523 1;81720 64500;81623 64530;81608 64613 1;81548 64845;81488 64980;81555 65205 1;81660 65573;81788 65730;81960 66068 1;81990 66143;82035 66188;82117 66180;82163 66180 18;84135 65730 1;84600 65835;84915 65948;85335 65708 1;85403 65670;85403 65535;85328 65498 1;84908 65340;84780 65040;84645 64613 1;84608 64500;84465 64387;84383 64470 1;84068 64770;83933 65025;83940 65453 1;83940 65573;83940 65715;84060 65723;84135 65730 18;74843 63832 1;74850 64035;74948 64200;75060 64192 1;75165 64192;75262 64012;75248 63810 33;75248 63615;75143 63450;75038 63457 1;74925 63457;74835 63637;74843 63832 18;79140 65190 1;78855 64965;78773 64733;78428 64635 1;78180 64575;78068 64492;77865 64343 1;77490 64080;77543 63675;77145 63457 1;76958 63367;76830 63578;76703 63735 1;76635 63818;76658 63915;76718 63998 1;76808 64148;76898 64207;76958 64373 1;76980 64448;77003 64500;76958 64552 1;76898 64620;76890 64665;76883 64740 1;76860 64845;76980 64860;77063 64920 1;77475 65273;77633 65520;78075 65835 1;78218 65948;78330 65955;78518 65948 1;78900 65940;79080 65783;79418 65580;79140 65190 18;79913 65992 1;79598 66165;79433 66255;79178 66495 1;79080 66585;79020 66727;79117 66818 1;79500 67193;79725 67335;80130 67680 1;80205 67755;80318 67852;80385 67762 1;80708 67313;80685 66960;81068 66548;79913 65992 18;76050 66030 1;76485 65633;76815 65393;76905 64785 1;76913 64710;76867 64635;76793 64582 1;76725 64552;76628 64537;76560 64560 1;76403 64643;76448 64800;76395 64950 1;76313 65145;76283 65250;76148 65385 1;75998 65535;76058 65700;75945 65858 1;75923 65895;75915 65933;75915 65963 1;75930 66038;75960 66075;76012 66038;76050 66030 18;69143 67950;72930 70605 1;74602 70965;73965 69128;74866 68433 1;74939 68377;74625 67815;74535 67793 1;74198 67733;74018 67725;73688 67770 1;73508 67800;73425 67883;73253 67883 1;73050 67883;72960 67845;72765 67838 1;72713 67838;72675 67793;72690 67740 1;72727 67500;72750 67373;72758 67125 1;72758 67005;72668 66960;72578 66878 1;72390 66735;72315 66645;72150 66473 1;72060 66390;72075 66308;72075 66188 1;72075 65865;72090 65648;71887 65385 1;71843 65332;71760 65370;71723 65423 1;71543 65693;71602 65895;71573 66210 1;71558 66330;71543 66398;71468 66473 1;71190 66735;70980 66825;70613 66848 1;70538 66855;70455 66833;70440 66900 1;70358 67155;70290 67290;70117 67485 1;70005 67613;69810 67755;69653 67710 1;69420 67665;69293 67710;69135 67635;69143 67943;69143 67950 18;70658 67200 1;70815 67073;70988 67012;71040 67073 1;71093 67125;71003 67290;70852 67425 33;70695 67560;70500 67635;70455 67583 1;70403 67515;70477 67320;70635 67178;70658 67200 18;72083 69983 1;72240 69840;72383 69773;72413 69555 1;72435 69360;72315 69210;72128 69150 1;71715 69030;71498 69015;71085 68918 1;70943 68887;70852 68798;70852 68655 1;70852 68512;71010 68468;71160 68468 1;71573 68483;71783 68588;72158 68768 1;72420 68903;72637 68933;72893 68775 1;73073 68663;73223 68633;73433 68700 1;73800 68828;73920 69036;73965 69426 1;74002 69786;73782 69624;73602 69924 1;73422 70224;73292 70023;72908 70230 1;72763 70308;72615 70193;72503 70313;72083 69983 18;79673 75315 1;79718 75120;79748 74992;79658 74805 1;79613 74723;79635 74663;79673 74565 1;79718 74430;79680 74295;79560 74220 1;79403 74130;79283 74175;79110 74205 1;78998 74227;78923 74213;78833 74145 1;78000 73590;77550 73358;76748 72765 1;76665 72713;76605 72765;76515 72765 1;76425 72773;76380 72788;76298 72818;79673 75315 1;79718 75120;79748 74992;79658 74805 1;79613 74723;79635 74663;79673 74565 1;79718 74430;79680 74295;79560 74220 1;79403 74130;79283 74175;79110 74205 1;78998 74227;78923 74213;78833 74145 1;78000 73590;77550 73358;76748 72765 1;76665 72713;76605 72765;76515 72765 1;76425 72773;76313 72818;76230 72848;79673 75315 18;75428 72300 1;75248 71813;74963 71655;74550 71340 1;74453 71273;74363 71333;74265 71385;75428 72300 1;75248 71813;74963 71655;74550 71340 1;74453 71273;74280 71378;74183 71430;75428 72300 18;82815 77798 1;82838 77633;82785 77512;82658 77400 1;82253 77070;82073 76867;81630 76598 1;81383 76455;81405 76193;81473 75915 1;81495 75818;81525 75720;81443 75660 1;81090 75428;80903 75308;80505 75188 1;80363 75150;80265 75120;80153 75203 1;80025 75293;79988 75367;79898 75480;82815 77798 18;79898 75480 1;79988 75367;80025 75293;80153 75203 1;80265 75120;80363 75150;80505 75188 1;80903 75308;81090 75428;81443 75660 1;81525 75720;81495 75818;81473 75915 1;81405 76193;81383 76455;81630 76598 1;82073 76867;82253 77070;82658 77400 1;82785 77512;82838 77633;82815 77798;86280 77955;86595 76823;88125 77093;89985 76545 32;90015 73095 32;88875 72420;87465 72203 32;89168 68550;90420 66930 32;92348 65805 32;97688 64012 32;98828 66390;98977 70193 32;99893 75285;83078 77940 1;83040 77468;83003 77137;83078 76590 1;83137 76095;83168 75840;83220 75338;86512 76725 1;86415 76695;86325 76680;86265 76748 1;86108 76920;86108 77055;85965 77227 1;85905 77295;85973 77400;86055 77415 1;86168 77445;86227 77475;86348 77505;86512 76725 18;87398 76463 1;87690 76448;87593 76117;87480 76095 1;87173 76058;86970 76080;86670 76043 1;86610 76043;86535 76050;86535 76110 1;86528 76245;86565 76313;86580 76440 1;86588 76553;86723 76545;86835 76538 1;87060 76530;87173 76500;87405 76463;87398 76463 18;87788 76178 1;87788 76298;87870 76395;87990 76395 1;88313 76395;88560 76515;88800 76283 1;88920 76163;88875 75908;88710 75855 1;88508 75803;88380 75848;88208 75953 1;88073 76035;87983 76028;87855 76095;87788 76178 18;87068 75180 1;86955 75023;86948 74895;86805 74768 1;86760 74745;86715 74753;86678 74768 1;86640 74798;86610 74835;86602 74865 1;86580 74925;86543 74985;86528 75038 1;86505 75113;86512 75173;86595 75195 1;86760 75285;86843 75352;87038 75352 1;87068 75352;87083 75330;87083 75285 1;87090 75255;87075 75218;87068 75180 18;87293 75030 1;87488 74850;87578 75458;87803 75293 1;87893 75233;87975 74400;87900 74318 1;87713 74123;87698 73973;87548 73755 1;87503 73703;87435 73605;87398 73658 1;87248 73845;87180 73943;87045 74137 1;86955 74265;86835 74348;86887 74490 1;86977 74745;87090 74843;87240 75068;87293 75030 18;88223 75090 1;88898 75262;89250 75323;89903 75570 1;90023 75623;90030 75315;89925 75240 1;89685 75083;89558 74992;89415 74745 1;89363 74663;89273 74655;89183 74678 1;88838 74790;88590 74685;88238 74648 1;88185 74648;88223 74715;88223 74760;88223 75090 18;87218 75090 1;87345 75300;87443 75443;87690 75473 1;87878 75503;88043 75480;88140 75293 1;88283 75023;88313 74887;88230 74633 1;88178 74490;88058 74333;87923 74393;87218 75090 18;88695 69360 1;88463 69278;88343 69240;88110 69173 1;88028 69158;87930 69113;87908 69188 1;87848 69352;87855 69450;87855 69615 1;87848 69953;87945 70178;88223 70358;88695 69360 18;86227 66795 1;86423 66795;86520 66855;86715 66818 1;86880 66788;86775 66570;86790 66390 1;86790 66315;87024 66274;87069 66192 1;87174 66004;86948 65918;86820 65813 1;86685 65708;86453 65708;86393 65865 1;86258 66195;86120 66278;86083 66624;86227 66795 18;89145 60818 1;89070 61177;88973 61328;88980 61688 1;88980 61778;89018 61778;89100 61808 1;89273 61898;89400 61867;89595 61800 1;90135 61628;90518 61523;91020 61800 1;91170 61890;91275 61875;91448 61860 1;91613 61853;91695 61838;91867 61830 1;91928 61830;91973 61800;92010 61740 1;92145 61530;92258 61433;92340 61185 1;92370 61088;92393 60998;92505 60975 1;93053 60893;93315 60742;93878 60742 1;93960 60742;94050 60735;94065 60645 1;94073 60593;94080 60563;94102 60503;91965 60390 1;92108 60533;92198 60623;92430 60630 1;92610 60637;92753 60518;92850 60345;91965 60390 18;92288 60113 1;92175 59948;92078 59835;91883 59820 1;91583 59805;91433 59753;91140 59783 1;90975 59805;90930 60023;90953 60180;92288 60113 18;95493 60343 1;95415 60757;95610 61119;95880 61082 1;96120 61052;96212 60605;96242 60357;95493 60343 18;95475 60542 1;95505 60812;95610 61119;95880 61082 1;96120 61052;96158 60804;96188 60556;87000 60270 1;87030 61200;86760 61733;87120 62580 1;87255 62910;87593 62873;87953 62895 1;88523 62940;88965 62760;89363 63173 1;89783 63623;90098 63938;90713 63908 1;91117 63893;91305 63750;91695 63600 1;91852 63540;91867 63383;91867 63203 1;91852 62948;91867 62685;92108 62580 1;92400 62460;92595 62625;92850 62423 1;93068 62250;93165 62153;93330 61920 1;93525 61650;93645 61478;93968 61380 1;94433 61245;94583 60878;94703 60398 1;94755 60180;94260 60188;94140 60367;94102 60503 33;94080 60563;94073 60593;94065 60645 1;94050 60735;93960 60742;93878 60742 1;93315 60742;93053 60893;92505 60975 1;92393 60998;92370 61088;92340 61185 1;92258 61433;92145 61530;92010 61740 1;91973 61800;91928 61830;91867 61830 1;91695 61838;91613 61853;91448 61860 1;91275 61875;91170 61890;91020 61800 1;90518 61523;90135 61628;89595 61800 1;89400 61867;89273 61898;89100 61808 1;89018 61778;88980 61778;88980 61688 1;88973 61328;89070 61177;89145 60818 32;89078 60720 1;88313 60675;87915 60615;87210 60323;87000 60270 18;88223 61200 33;87923 61508;87675 61965;87420 62438 1;87315 62625;87180 62693;87128 62850 32;87210 62970 1;87398 63075;87518 63090;87705 63203 1;87810 63278;87885 63353;87878 63480 1;87848 63698;87818 63795;87765 63998 1;87720 64133;87915 64177;88058 64170 1;88238 64162;88335 64035;88380 63855 1;88477 63427;88530 63218;88590 62775 1;88620 62505;88673 62340;88560 62085 1;88410 61778;88410 61448;88395 61103;88223 61200 50;91140 64050 1;91170 63998;91140 63953;91140 63885;91140 63832 33;91012 63878;90878 63908;90713 63908 1;90098 63938;89783 63623;89363 63173 32;89265 63075 1;89213 62648;89295 62430;89333 61995;89318 61867 33;89250 61867;89175 61853;89100 61808 1;89018 61778;88980 61778;88980 61688 1;88973 61328;89070 61177;89145 60818 32;88875 60713 1;88740 60690;88620 60585;88545 60690 1;88470 60787;88485 60870;88440 60975;88395 61103 33;88410 61448;88410 61778;88560 62085 1;88673 62340;88620 62505;88590 62775 1;88575 62865;88560 62940;88553 63015 32;88538 63082 33;88492 63345;88448 63540;88380 63855 1;88335 64035;88238 64162;88058 64170 1;87968 64177;87863 64162;87803 64125 32;87742 64102 1;87668 64268;87660 64365;87683 64537 1;87698 64695;87765 64815;87923 64852 1;88163 64920;88290 64942;88545 64950 1;88770 64965;88725 65302;88958 65355 1;89130 65400;89235 65265;89415 65302 1;89790 65393;90000 65453;90383 65370 1;90510 65348;90585 65302;90660 65190 1;90908 64800;90938 64552;91117 64117;91140 64050 18;87548 67688 1;88477 66870;88988 66405;90188 66060;91898 62258 1;92018 62220;91950 62025;91860 61927;91762 61838 33;91650 61845;91575 61860;91448 61860 1;91275 61875;91170 61890;91020 61800 1;90518 61523;90135 61628;89595 61800 1;89498 61838;89423 61860;89348 61867 32;89310 62183 1;89303 62228;89325 62258;89370 62258 1;89753 62258;89940 62220;90330 62190 1;90983 62145;91313 62302;91980 62273;91898 62258 18;107783 61703;106455 61305;105885 62887 32;106530 63255;107783 61703 18;106583 63278;105885 62887 32;106455 61305;99023 52508 1;98977 52830;98948 52988;98910 53302 1;98895 53378;98955 53445;99030 53445 1;99645 53475;99960 53408;100583 53325 1;100658 53318;100762 53355;100748 53423 1;100583 54023;100508 54315;100387 54915 1;100365 55012;100410 55140;100508 55125 1;100665 55103;100740 55058;100898 54998 1;101070 54938;101085 54780;101167 54608 1;101400 54098;101505 53828;101625 53265 1;101670 53033;101580 52898;101475 52673;99023 52508 18;98273 54457 1;98378 54660;98445 54780;98430 54998 1;98422 55058;98468 55088;98528 55095 1;98843 55185;98977 55328;99218 55552 1;99248 55590;99308 55530;99315 55478 1;99330 55223;99360 55095;99398 54832 1;99405 54773;99390 54540;99330 54533 1;99172 54525;99113 54653;98977 54578 1;98753 54465;98625 54465;98385 54465;98273 54457 18;99262 55545 1;99712 55635;99968 55785;100417 55658 1;100515 55635;100583 55575;100613 55470 1;100658 55298;100733 55223;100748 55035 1;100748 54885;100538 55080;100395 55035 1;100065 54953;99765 54585;99518 54443 1;99420 54390;99405 54503;99315 54555;99262 55545 18;98565 54585 1;98738 54105;98813 53873;98895 53385 1;98813 53378;98723 53370;98625 53370 1;98393 53370;98273 53355;98063 53423 1;97755 53520;97643 53738;97545 54037 1;97508 54143;97493 54195;97462 54300 1;97440 54360;97448 54435;97508 54435;97538 54435 1;97868 54443;97958 54548;98295 54555 1;98393 54563;98468 54578;98565 54585 18;99615 53423;99540 54465 32;99600 54503 33;99810 54660;100065 54945;100350 55028 32;100387 54915 33;100508 54315;100583 54023;100748 53423 1;100762 53355;100658 53318;100583 53325 1;100215 53378;99953 53423;99683 53445;99615 53423 18;98977 52650;98977 52808 1;98955 52965;98933 53108;98910 53302;98835 53378 1;98775 53378;98700 53370;98625 53370 1;98393 53370;98273 53355;98063 53423 1;97755 53520;97643 53738;97545 54037 1;97508 54143;97493 54195;97462 54300 1;97440 54360;97448 54435;97508 54435;97538 54435 1;97868 54443;97958 54548;98295 54555;98415 54570 1;98475 54578;98528 54585;98602 54585 1;98880 54608;99008 54690;99233 54623 1;99360 54585;99413 54548;99540 54480 1;99600 54450;99608 54420;99615 54345 1;99630 53978;99660 53933;99667 53558 1;99667 53498;99667 53415;99608 53415 32;99743 53445 1;99990 53423;100238 53378;100583 53325 1;100613 53325;100650 53332;100680 53340 33;100725 53363;100755 53385;100748 53423 1;100718 53512;100695 53595;100672 53677;100628 53865 1;100538 54210;100470 54480;100387 54915 1;100365 55012;100410 55140;100508 55125 1;100665 55103;100740 55058;100898 54998 1;101070 54938;101085 54780;101167 54608 1;101400 54098;101505 53828;101625 53265 1;101655 53093;101610 52973;101542 52823 32;93480 52238;93908 53168 32;94965 53228 32;95242 52927 32;94725 52155;93480 52238 18;98415 53355 1;98258 53205;98198 53063;97988 53003 1;97913 52988;97905 52867;97965 52815 1;98085 52710;98160 52635;98183 52470;98047 52305 33;97830 52283;97523 52358;97283 52328 1;95175 52125;94463 51915;92595 52455 32;92325 52530 33;91867 52695;91523 52853;91163 53018 32;91170 53078 33;91215 53175;91238 53250;91298 53355 1;91320 53423;91365 53453;91440 53453 1;91583 53453;91658 53438;91808 53438 1;91883 53438;91935 53505;91943 53580 1;91943 53662;91950 53723;91958 53783 32;91845 53820 1;91455 54098;91433 54443;91373 54908 1;91335 55170;91313 55177;91373 55433 1;91403 55613;91815 55740;91852 55860 1;91928 56093;91823 56438;91770 56753 1;91703 57060;91695 57375;91710 57623 1;91755 58245;91958 58725;92198 59460;92273 59512 32;92992 59168 32;93090 59340 32;93210 59393 1;93600 59655;93773 59820;94193 60037 1;94335 60120;94575 60255;94613 60082;94650 60023 33;94665 59798;94650 59490;94867 59490 32;95063 59378 33;95333 59355;95475 59325;95835 59235 1;96413 59108;96750 58845;96968 58313 1;97215 57698;97268 57345;97297 56677 32;97283 56535 33;97283 56378;97238 56302;97260 56137 1;97260 56078;97275 56018;97290 55965 32;97283 55740 1;97297 55440;97313 55283;97320 54975;97320 54818 33;97335 54668;97380 54578;97425 54412 32;97462 54300 33;97493 54195;97508 54143;97545 54037 1;97643 53738;97755 53520;98063 53423 1;98160 53393;98235 53378;98318 53378 32;98415 53355 18;95310 60120;97208 60075 32;97215 59963 33;97268 59550;97283 59302;97403 58845 1;97545 58275;97740 57938;97770 57345 1;97778 57105;97792 57098;97613 56933 1;97485 56828;97350 56775;97297 56655 32;97290 56738 33;97260 57367;97208 57720;96968 58313 1;96750 58845;96413 59070;95835 59198 1;95393 59310;95273 59355;94830 59400 32;94867 59490 32;94988 59520 33;95137 59595;95205 59805;95265 60008;95310 60120 18;98573 52365 1;99278 52440;99938 52515;100815 52590 1;102773 52515;103672 52568;105645 52350 1;106800 52223;107385 51990;108405 51420 1;109658 50723;109965 50213;111165 49410 1;112042 48818;112868 48608;113925 48473 1;114683 48383;115185 48173;115815 47730 1;116408 47318;116760 46883;117308 46620 1;117727 46425;117983 46162;118185 45990;89753 53745 1;89895 53805;89963 53865;90128 53873 1;90262 53887;90398 53940;90473 53820 1;90548 53693;90443 53580;90360 53445;89753 53745 18;89963 57480;84833 56933 1;84810 57060;84855 57188;84983 57218 1;85380 57330;85620 57353;85943 57608 1;86153 57780;86288 57818;86512 57975 1;86588 58035;86678 57938;86708 57840 1;86805 57480;86790 57278;86813 56895 1;86820 56707;86828 56610;86798 56423 1;86768 56295;86670 56198;86543 56213 1;85898 56295;85605 56483;85005 56723 1;84893 56768;84833 56783;84810 56895;84833 56933 18;84818 58733;84930 58762 33;84960 58320;84870 58028;85140 57668 1;85238 57540;85283 57473;85380 57338 32;84810 57052 33;84593 57308;84548 57480;84323 57713 1;84262 57773;84195 57855;84135 57795 1;83933 57630;83775 57623;83580 57450 1;83528 57412;83453 57383;83415 57435 1;83370 57495;83340 57525;83310 57563 32;83280 57623 32;84053 58148;84818 58733 18;85890 59340 1;85943 59025;85973 58823;86198 58560 1;86355 58380;86438 58260;86558 58065 32;86550 57998 33;86288 57818;86153 57780;85943 57608 1;85755 57465;85590 57398;85418 57338 32;85380 57338 33;85283 57473;85238 57540;85140 57668 1;84878 58020;84953 58298;84930 58718 32;84923 58808 32;85875 59423;85890 59340 18;87878 54787;86820 55020 32;86378 55005 32;84975 54742 32;84533 54585 32;84053 54405 32;84023 54495 33;83745 55440;83910 56250;84780 56828 32;84900 56768 33;84930 56753;84960 56745;85005 56723 1;85605 56483;85898 56295;86543 56213 1;86670 56198;86768 56295;86798 56423 1;86813 56558;86820 56648;86813 56760 32;86805 56992 33;86790 57315;86790 57518;86708 57840 1;86685 57908;86633 57975;86580 57990 32;86565 58043 33;86445 58253;86363 58373;86198 58560 1;85958 58845;85943 59063;85875 59423 32;86558 59753 32;87240 60030 32;87270 59948 33;87315 59790;87413 59640;87570 59685 1;88035 59850;88283 59895;88755 60075 1;88905 60143;88980 60262;89003 60420 32;89438 60427 32;89445 60315 33;89453 59835;89430 59558;89385 59033 1;89355 58808;89303 58665;89415 58455 1;89543 58215;89685 58073;89835 57832 1;89880 57750;89865 57615;89775 57578 1;89295 57398;88920 57488;88492 57218 1;88313 57113;88290 56955;88260 56745 1;88133 56010;87975 55635;87923 54915;87878 54787 18;90735 52568 1;91140 52537;91358 52455;91710 52238 1;92250 51908;92468 51653;93008 51300;81742 56325;82470 57060 32;83235 57630 32;83310 57563 33;83340 57525;83370 57495;83415 57435 1;83453 57383;83528 57412;83580 57450 1;83775 57623;83933 57630;84135 57795 1;84195 57855;84262 57773;84323 57713 1;84548 57480;84593 57308;84810 57052 32;84810 56843 32;84900 56768 33;84930 56753;84960 56745;85005 56723 1;85605 56483;85898 56295;86543 56213 1;86580 56213;86625 56220;86655 56235 32;86843 54998 32;86348 54983 32;84983 54735 32;84555 54585 32;83295 54150 32;82875 54015 32;81548 53603 32;81495 53490 32;81495 53610 33;81495 53670;81503 53715;81518 53775 1;81578 54158;81690 54330;81720 54705 1;81735 54975;81630 55110;81630 55373 1;81623 55537;81765 55598;81765 55755 1;81758 55943;81750 56040;81750 56205;81742 56325 18;84833 56933 1;84810 57060;84855 57188;84983 57218 1;85380 57330;85620 57353;85943 57608 1;86153 57780;86288 57818;86512 57975 1;86588 58035;86678 57938;86708 57840 1;86805 57480;86790 57278;86813 56895 1;86820 56707;86828 56610;86798 56423 1;86768 56295;86670 56198;86543 56213 1;85898 56295;85605 56483;85005 56723 1;84893 56768;84833 56783;84810 56895;93023 59205;97297 56655 1;97283 56625;97275 56588;97283 56535 1;97283 56378;97238 56302;97260 56137 1;97275 55995;97297 55898;97425 55808 1;97538 55733;97620 55755;97755 55718 1;97883 55688;97950 55523;97890 55403 1;97800 55245;97680 55223;97515 55140 1;97455 55117;97403 55088;97365 55050 32;97320 54975 32;97320 54818 33;97335 54668;97380 54578;97425 54412 32;97462 54300 33;97493 54195;97508 54143;97545 54037 1;97643 53738;97755 53520;98063 53423 1;98160 53393;98235 53378;98318 53378 32;98415 53355 1;98258 53205;98198 53063;97988 53003 1;97913 52988;97905 52867;97965 52815 1;98070 52725;98145 52650;98167 52515 32;98175 52425 32;97305 52335 32;96683 52268 32;95385 52140 32;94778 52103 32;94725 52155 32;95242 52927 32;94965 53228 32;93908 53168 32;93525 52343 32;93503 52260 32;93413 52260 32;92955 52343 32;91680 52762 32;91133 52980 33;91208 53130;91223 53213;91298 53355 1;91320 53423;91365 53453;91440 53453 1;91583 53453;91658 53438;91808 53438 1;91883 53438;91935 53505;91943 53580 1;91958 53835;92003 53955;92085 54195 1;92175 54495;92310 54608;92483 54863 1;92520 54923;92475 54998;92415 55020 32;92880 59205;93023 59205 18;97275 56625;92977 59175 32;93015 59220 32;93083 59332 32;93510 60045 32;94635 60105 32;94650 60023 33;94665 59798;94650 59490;94867 59490 32;95018 59385 33;95318 59355;95460 59332;95835 59235 1;96413 59108;96750 58845;96968 58313 1;97208 57713;97260 57360;97290 56723;97275 56625 18;103433 60600;103823 59543 1;103658 59475;103515 59400;103387 59512 1;103163 59700;103133 59768;103005 60023 1;102885 60255;102503 60503;102292 60668;103433 60600 18;78615 77933 1;78630 77843;78645 77753;78668 77655 1;78810 76950;78945 76605;78990 75870 1;79005 75293;78990 74385;79545 74535 1;80250 74730;80528 75060;81030 75593 1;81375 75975;81727 76020;82245 76012 1;82590 76012;82867 76050;83085 75773 1;83220 75600;83528 75683;83625 75870 1;83835 76343;84000 76553;84367 76913 1;84795 77363;85073 77640;85463 77955;92175 77970 1;92438 77730;92678 77483;92948 77093 1;93480 76305;93885 76005;94568 75315 1;95205 74655;95775 74625;96645 74295 1;97260 74063;97650 73815;98265 73590 1;98505 73515;98505 73275;98190 72953 1;97988 72773;97950 72510;98085 72270 1;98198 72083;98348 72060;98505 71895 1;98715 71670;98887 71520;99210 71535 1;99458 71550;99540 71730;99750 71895 1;100320 72352;100545 72660;101167 73050 1;101775 73455;102060 73695;102727 73995 1;103725 74460;104295 74790;105405 74715 1;106140 74670;106590 74730;107205 74310;73275 77528 1;73403 76950;73688 76523;73710 75795 1;73718 75030;73230 74730;72750 74130 1;72165 73433;71685 73043;71685 72135 1;71685 71715;71715 71430;72008 71115 1;72637 70425;73500 70575;74370 70950 1;75135 71303;75578 71415;76268 71910 1;76770 72285;76995 72540;77588 72735 1;78578 73073;79095 73245;80025 73733 1;80940 74220;81338 74670;82365 74835 1;82740 74903;83010 74775;83227 74453 1;83385 74213;83670 74010;83925 74175 1;84240 74385;84367 74602;84450 74970 1;84570 75593;84570 75990;85005 76433 1;85538 76980;85778 77303;86408 77730 1;86535 77820;86648 77895;86760 77963;91343 77963 1;91755 77565;91898 77250;92325 76793 1;92790 76290;92955 75975;93225 75330 1;93510 74655;93660 74265;94208 73755 1;94680 73320;95108 73410;95708 73170 1;96420 72893;96690 72563;97268 72053 1;97958 71445;98318 71130;98910 70410 1;99008 70283;99188 70305;99330 70395 1;99870 70800;100118 71040;100688 71415 1;101528 71970;101940 72270;102810 72795 1;103470 73200;103905 73185;104670 73335 1;105540 73515;105998 73575;106890 73470 1;107280 73350;107528 73313;107813 73005;92970 77970 1;93548 77288;93953 76793;94748 76095 1;95738 75225;96540 75210;97808 74790 1;98385 74602;98820 74505;99105 73950 1;99225 73710;99278 73590;99390 73335 1;99488 73095;99840 73095;100050 73253 1;100650 73733;100935 73995;101625 74333 1;102555 74813;103080 74963;104108 75173 1;104977 75360;105420 75585;106305 75510 1;106837 75473;107130 75435;107625 75210 1;107993 75038;108045 74730;108172 74333 1;108360 73733;108480 73148;109110 73058 1;109688 72983;110025 72998;110558 73245 1;110970 73448;111248 73583;111428 74003 1;111623 74475;111600 74745;111667 75248 1;111690 75480;111743 75675;111968 75742 1;112208 75818;112335 75803;112605 75833;113160 53250;113565 52305;113468 53550;113820 52403 1;113587 52268;113393 52320;113145 52403 1;112980 52463;112935 52620;112913 52785 1;112860 53093;112868 53250;112852 53558;113468 53550 18;113520 53198;113828 52410 33;113550 52215;113250 52373;113145 52403 1;112980 52463;112935 52620;112913 52785 1;112890 52920;112875 53025;112868 53123 32;112852 53250 32;113137 53205;113520 53198 18;114255 50985;112950 51758;112583 51037;114893 49957;114533 49335 1;114435 49500;114398 49590;114270 49725 1;114188 49815;114090 49808;113985 49778 1;113602 49680;113408 49575;113018 49582 1;112785 49590;112605 49628;112508 49823 1;112268 50280;112230 50543;112125 51037 1;112087 51195;112350 51188;112500 51128 1;113378 50798;113738 50438;114623 50093 1;114743 50048;114825 50048;114930 49950 1;115140 49748;115238 49582;115245 49283 1;115245 49170;115102 49140;114990 49140;114533 49335 18;111225 53512;112005 53363 1;112193 53302;112020 53198;112035 53010 1;112035 52875;112012 52853;111990 52710 1;111878 52155;111938 51825;112155 51293 1;112208 51165;112403 50963;112080 50940 1;111750 50918;111563 51075;111375 51338 1;111068 51773;111210 52117;111225 52643 1;111233 53093;110955 53287;110625 53573;111225 53512 18;112868 53168 33;112875 53055;112883 52935;112913 52785 1;112935 52620;112980 52463;113145 52403 1;113363 52335;113542 52283;113738 52365 32;113880 52380 1;114292 51465;114563 51023;114863 50055 1;114893 49957;114698 50048;114608 50085 1;113940 50408;113618 50588;112950 50887 1;112703 51000;112560 51075;112297 51098 1;112133 51120;112073 51278;112035 51427 1;111953 51698;111960 51848;111938 52117 1;111885 52575;112005 52815;112155 53242;112868 53168 50;118710 48150 32;118643 47520 32;119760 47453 32;120030 47355 1;119962 47048;119723 46912;119415 46845 1;119100 46785;118890 46853;118643 47040 1;118065 47475;117705 47595;117060 47895 1;116797 48023;116700 48203;116663 48480;118710 48150 50;115178 49207 1;115238 49207;115290 49177;115297 49110 1;115305 48975;115395 48923;115440 48787 1;115462 48705;115583 48585;115500 48578 1;115095 48555;114840 48795;114675 49162;115178 49207 18;106943 55170 33;107385 54832;107708 54660;107962 54533 32;108098 54375 1;107977 54113;107917 53940;107685 53768 1;107580 53700;107535 53610;107550 53483 1;107558 53348;107587 53258;107528 53130 1;107422 52943;107205 53018;106988 53033 1;106553 53078;106365 53265;105938 53302 1;105593 53340;105383 53280;105098 53460 1;104910 53580;104962 53873;105135 54000 1;105368 54188;105510 54255;105803 54338 1;106297 54488;106462 54802;106725 55253;106943 55170 50;108262 56348 1;108705 56430;108938 56370;109387 56385 1;109538 56393;109635 56220;109605 56063 1;109500 55628;109440 55403;109297 54975 1;109223 54780;109133 54623;108922 54593 1;108743 54570;108653 54653;108518 54758 1;108300 54930;108255 55073;108045 55238 1;107933 55328;107828 55373;107813 55508 1;107775 55748;107775 55867;107760 56100;108262 56348 18;107685 56242 1;107145 56558;106733 56528;106328 56985 1;106185 57150;106148 57255;106058 57450 1;105938 57698;105908 57870;105690 58020 1;105547 58117;105495 58238;105518 58403 1;105547 58778;105465 59145;105113 59242 1;104775 59340;104587 59280;104265 59385 1;104033 59468;103973 59617;103845 59820 1;103672 60090;103613 60248;103508 60540 1;103470 60637;103560 60720;103658 60735 1;104100 60840;104333 60818;104783 60923 1;104977 60975;105068 61028;105278 61035 1;105540 61050;105720 61103;105945 60945 1;106538 60533;106845 60315;107295 59738 1;107595 59348;107738 59137;107925 58673 1;108045 58373;108180 58193;108495 58073 1;108720 57990;108953 58035;109035 57802 1;109102 57585;109178 57473;109178 57233 1;109163 56910;108900 56760;108593 56655 1;108413 56603;108337 56543;108165 56483;107685 56242 18;106508 56880 1;106305 56550;106230 56363;105960 56085 1;105885 56018;105833 56198;105833 56287 1;105788 56940;105765 57323;105405 57855 1;105285 58028;105240 58133;105098 58275 1;104730 58643;104618 58898;104318 59310 1;104273 59378;104385 59445;104460 59430 1;104887 59385;105278 59453;105473 59063;106508 56880 18;107078 56040;106680 55935 32;105915 55635 32;105960 56085 33;106178 56318;106268 56490;106410 56723 32;106440 56783 32;106508 56880 32;107738 56265;107078 56040 18;107520 56332 33;107055 56558;106688 56580;106328 56985 1;106185 57150;106148 57255;106058 57450 1;105938 57698;105908 57870;105690 58020 1;105547 58117;105495 58238;105518 58403 1;105547 58778;105465 59145;105113 59242 1;104858 59318;104693 59302;104498 59332;107768 55935 33;107775 55800;107783 55688;107813 55508 1;107828 55373;107933 55328;108045 55238 1;108255 55073;108315 54915;108533 54742 1;108585 54705;108495 54765;108547 54735;109365 55230 1;109665 54870;109875 54735;110212 54390 1;110288 54315;110273 54143;110167 54120 1;109883 54068;109755 53985;109500 53865 1;109275 53768;109125 53835;108900 53903 1;108675 53978;108630 54128;108473 54293 1;108420 54345;108330 54353;108352 54412 1;108398 54578;108443 54660;108533 54802;109365 55230 18;111698 56490 1;111585 55853;111608 55598;111518 54998 1;111443 54578;111675 54008;111255 53963 1;111105 53955;111083 54135;111038 54270 1;110843 54818;110745 55110;110378 55545 1;110190 55762;110040 55845;109928 56100 1;109868 56228;110040 56318;110175 56325 1;110602 56370;110820 56393;111225 56550;111698 56490 18;109477 57503 1;109515 57555;109620 57585;109643 57518 1;109688 57345;109710 57255;109725 57075 1;109733 56933;109875 56760;109740 56715 1;109410 56625;109230 56648;108900 56633;109477 57503 18;106628 61133 1;106898 60855;107040 60645;107430 60585 1;107760 60540;107955 60533;108233 60330 1;108420 60188;108570 60180;108818 60188 1;108983 60195;109028 60045;109133 59903 1;109268 59707;109275 59565;109313 59318 1;109403 58650;109605 58328;109583 57645 1;109575 57548;109462 57548;109395 57473 1;109313 57405;109275 57308;109178 57330;109155 57443 33;109125 57563;109080 57660;109035 57802 1;108953 58035;108720 57990;108495 58073 1;108180 58193;108045 58373;107925 58673 1;107738 59137;107595 59348;107295 59738 1;106845 60315;106538 60533;105945 60945 1;105870 60998;105795 61028;105727 61043 32;105870 61140;106628 61133 18;105945 60945 33;106538 60533;106845 60315;107295 59738 1;107595 59348;107738 59137;107925 58673 1;108045 58373;108180 58193;108495 58073 1;108720 57990;108953 58035;109035 57802 1;109073 57683;109110 57600;109133 57503;108023 61365;108818 60188 33;108570 60180;108420 60188;108233 60330 1;107955 60533;107760 60540;107430 60585 1;107055 60645;106905 60840;106658 61095 32;106635 61162 32;107970 61463;108023 61365 18;112875 53603;112875 53250 33;112598 53258;112358 53258;112125 53295 1;111833 53355;111608 53475;111345 53558 32;111172 53670 1;111195 53783;111218 53828;111248 53933;112875 53603 18;109395 55290 33;109470 55545;109523 55748;109605 56063 1;109635 56220;109538 56393;109387 56385 1;109065 56378;108855 56408;108608 56393;109598 57525 1;109448 57383;109320 57188;109148 57285 1;108840 57457;108428 57780;108675 58020 1;108922 58275;109095 58350;109425 58478;109598 57525 18;109365 61425;109410 60930 32;109762 60908;109883 61253;109898 61508;109470 60983;109433 61718 32;109830 61740 32;109770 60968;109470 60983 18;111983 62662;111990 63525 32;112538 63503 32;112830 62873;112073 62520;112050 63465 32;112485 63435 32;112830 62662;112073 62520 18;116640 63818;116670 64567 32;117698 64537;116730 63555;116730 64500 32;117885 64440;116730 63555 18;122198 65310;122265 66060 32;122723 66015 32;122648 65273 32;122198 65310 18;121718 65093;121748 65535 32;122625 65468 32;122745 65033;121792 64860;121823 65460 32;122558 65408 32;122723 64800;121792 64860 18;124485 56730;121238 57135;121628 59468;123300 59235 1;123255 58973;123210 58800;123000 58635 1;122745 58455;122550 58433;122250 58455 1;121920 58485;121733 58635;121560 58912;121628 59468 18;123068 57008 1;123225 57195;123390 57262;123637 57225 1;123870 57195;123990 57090;124133 56887;123068 57008 18;121462 57908 1;121672 57675;121778 57495;121762 57173;121358 57218;121462 57908 18;121560 58912 1;121733 58635;121920 58485;122250 58455 1;122550 58433;122745 58455;123000 58635 1;123210 58800;123255 58973;123300 59235;123132 57085 1;123289 57272;123390 57262;123637 57225 1;123870 57195;123926 57205;124069 57002;121564 57793 1;121774 57560;121778 57661;121762 57339;124485 56745;121320 57165;121560 59505 32;124485 59145;124493 56745;124485 56745 18;124058 54427;123990 53738;122415 54832;122795 54795;122693 53723 16;121538 54427;121500 53895;124493 53610;124050 53498;124133 54383 32;124500 54360;124500 53610;124493 53610 18;121568 53617;121643 54840 32;122738 54750 32;122580 53498;121568 53617 18;121635 53048;121620 52845 32;121380 52823 32;121365 51787 32;119820 51030 32;119887 50693 32;119025 50430 32;117938 50468 32;117637 50108 32;116955 50130 32;116790 50595 32;116903 51218 32;117555 51555 32;118297 51570 32;118590 51810;120922 53198;120915 52110 32;119723 51540 32;119460 51728;121568 53400;121538 52898 32;121358 52853 32;121328 51750 32;120113 51120 32;119813 50677 32;119093 50423 32;117953 50460 32;117840 50363 32;117637 50108 32;116955 50130 32;116790 50595 32;116903 51218 32;117555 51555 32;118297 51570 32;118553 51787 32;119468 51765 32;119678 51570 32;121005 52140 32;121005 53453;121568 53400 18;118095 54555;117090 54623 32;117120 55335;118950 54878;119047 55957;119602 55808;119955 55785 32;119910 55238 32;119558 55260 32;119602 55808 18;119640 55328;119565 54563;118283 54637;117165 54705 32;117225 55478;118283 54637 18;119910 55283;119858 54473 32;119573 54593 32;119648 55343;119910 55283 18;119010 54608;119123 55838 32;119610 55778 32;119468 54360;119010 54608 18;116753 55568;115020 55740 32;115058 56153 32;116273 56033;115485 56130;115553 57000;117023 55628;115087 55793 32;115118 56115 32;115545 56085 32;115672 57278;117023 55628 18;115125 58718;113212 58912 32;113235 59130 32;115140 58898;115125 58718 18;114998 60488;114308 60585 32;114352 61088 32;115080 60990;117135 57098;116640 57630 32;116145 57600;116318 61973;116512 61710 32;117045 61650;115253 60540;114375 60637 32;114398 61005 32;115320 60878;115253 60540 18;115988 57503;116618 57555 32;117030 57113 32;116528 56670;115988 57503 18;116925 63300;117210 62963 32;117023 61695 32;116565 61762 32;116183 62310;116925 63300 18;124493 54427;124080 54465 32;123990 53760 32;122670 53670 32;122783 54795 32;121590 54908 32;121508 53873 32;120600 54158 32;120908 57143 32;124493 56760;124500 54427;124493 54427 18;124477 59153;121545 59543 32;121395 58380 32;120360 58463 32;120075 55853 32;119018 55890 32;118935 54923 32;117810 55695 32;116693 56730 32;117083 57105 32;116693 57563 32;116010 57608 32;115658 58748 32;115808 60600;116227 62048;116468 61785 32;117045 61650 32;117330 62992 32;117262 63300 32;117922 63870 32;119415 64335 32;122408 64335 32;124470 63818;124485 59153;124477 59153 18;100193 40162 1;99727 39803;99480 39630;98970 39330 1;98505 39060;98227 38895;97988 38415 1;97380 36720;96795 35790;97028 34020;110587 34073 1;110715 34155;110850 34238;111000 34320 1;111630 34703;111998 34815;112672 35115 1;112792 35175;112845 35295;112808 35423 1;112448 36510;112245 37103;112365 38235;91136 40984;91114 41531 32;91586 41554 32;91601 41006 32;91136 40984 18;100184 42976;101369 43231 32;101466 42758 32;100274 42503 32;100184 42976 18;109995 39923;111188 39878 32;111150 39045 32;110310 39082 32;110318 39420 32;109973 39443 32;109995 39923 18;121193 58320;121365 58298 32;121260 57255 32;121080 57278;121193 58320 18;116385 44813;116280 46785 1;114150 46890;113070 46860;111000 47332 1;110190 47520;109792 47610;108990 47798 1;108810 47843;108758 47940;108630 48060;99750 44610 1;100170 44700;100613 44805;101167 44933 1;101925 45120;102315 45293;102968 45728 1;103433 46035;103553 46125;104025 46193 1;104895 46328;105398 46380;106328 46388 1;108885 46433;110063 45938;112620 45720;109185 48300 1;109628 48338;109852 48405;110295 48353 1;110393 48345;110520 48315;110505 48210 1;110453 47978;110295 47835;110055 47798 1;109740 47753;109448 47707;109283 47970 1;109208 48090;109110 48158;109155 48278;109185 48300 18;107280 48968 1;107483 48960;107640 48848;107633 48728 1;107633 48615;107498 48473;107295 48488 33;107100 48495;106905 48653;106913 48765 1;106913 48885;107085 48983;107280 48968 18;107738 47759;105855 47856;92348 50498 1;92183 50475;92123 50378;91965 50378 1;91860 50385;91808 50490;91755 50573 1;91590 50828;91598 50992;91470 51255 1;91403 51383;91500 51510;91635 51563 1;91785 51630;91928 51630;92040 51503 1;92250 51255;92265 51060;92348 50738 1;92370 50648;92430 50520;92340 50490;92348 50498 18;93578 52223 1;93540 52020;93510 51637;93308 51668 1;93038 51713;92910 52170;92850 52425;93578 52223 18;84203 50093 1;84285 50242;84495 50145;84623 50025 1;85110 49552;85230 49207;85665 48683 1;85755 48578;85710 48383;85575 48330 1;85170 48195;84945 48195;84540 48082 1;84405 48052;84308 48052;84210 48143 1;84045 48300;84000 48405;83843 48563 1;83678 48728;83640 48923;83730 49133 1;83880 49523;84015 49695;84188 50070;84203 50093 18;83498 48870 33;84225 49193;84660 49365;85793 49650 1;86153 49740;86325 49695;86685 49815 1;87788 50205;88230 50565;89310 51015 1;90113 51360;90585 51653;91110 52193 32;91305 52320 1;91643 52185;91778 52043;92093 51840 1;92242 51750;92235 51600;92235 51412;92190 51270 33;92153 51353;92108 51427;92040 51503 32;91980 51555 33;91883 51630;91755 51623;91635 51563 1;91500 51510;91403 51383;91470 51255 1;91568 51052;91583 50903;91673 50723 32;91710 50610 1;91418 50498;91260 50468;90960 50385 1;89820 50108;89242 49995;88080 49912 1;87968 49905;87878 49830;87885 49718 1;87893 49560;87870 49478;87863 49313 1;87840 49095;87690 48983;87488 48908 1;86940 48720;86655 48668;86108 48518 1;85762 48427;85755 48090;85433 47940 1;85223 47850;85110 48105;84893 48082 1;84690 48068;84578 47993;84398 48060 1;83918 48255;83745 48480;83355 48795;83498 48870 50;83610 44588 1;84308 44760;84698 44768;85410 44625;88328 44423 1;87803 43800;87360 43508;87233 42698;95670 46875 1;95588 46770;95550 46710;95475 46598 1;95438 46568;95400 46545;95363 46553 1;95318 46553;95280 46568;95250 46598 1;95130 46710;95025 46733;94973 46875 1;94943 46943;94935 47003;94935 47048 1;94935 47115;94943 47175;95003 47220 1;95063 47303;95085 47363;95183 47400 1;95288 47460;95378 47430;95498 47370 1;95573 47332;95617 47295;95700 47235 1;95730 47220;95753 47183;95753 47138 1;95760 47108;95745 47070;95738 47018 1;95708 46973;95693 46943;95670 46890;95670 46875 18;94950 46957 1;94733 47152;94455 47190;94313 47363 1;94253 47445;94313 47745;94403 47783 1;94523 47843;94867 47820;94995 47768 1;95175 47700;95205 47543;95325 47378;94950 46957 18;102893 47858 1;103012 47895;103020 47978;103028 48037 1;103073 48248;103118 48465;103313 48540 1;103545 48653;103733 48555;103965 48443 1;104167 48360;104295 48420;104520 48480 1;104678 48533;104850 48488;104910 48653 1;104948 48773;104993 48930;105135 48960 1;105278 48998;105323 48945;105443 48848 1;105547 48765;105683 48653;105788 48555;103755 47100 1;103417 46853;103215 46777;102840 46598 1;102637 46508;102525 46500;102315 46455 1;101873 46380;101633 46500;101212 46628 1;100823 46748;100620 46868;100320 47138 1;100238 47213;100387 47348;100500 47332 1;100643 47318;100718 47250;100860 47280 1;101610 47460;101970 47595;102720 47805 1;103178 47940;103380 47505;103762 47213;103755 47100 18;105741 43279;105210 46148 32;103665 45893;102345 45045;97583 44123 32;92226 43370 32;89579 43106;88851 42674 32;88282 41889;88302 41376;89016 40811;89808 40565;92475 40692 32;97361 41391;97728 41725;101055 42329 32;105741 43279 18;98346 43880;98429 43490 32;98031 43422 32;97949 43797 32;98346 43880 18;97299 43761;97382 43356 32;96969 43281 32;96887 43679 32;97299 43761 18;95595 34020;95400 35513;95438 36923 32;95460 37560;96165 39255;95850 39795 32;88463 39450 32;88497 37321 32;88508 36630;88538 35287;88628 34755;88755 33998;92595 37245;93075 37253 32;93098 36405 32;92617 36405 32;92595 37245 18;96122 41205;96225 40418 32;90075 40125 32;90009 40568 32;92498 40628;96122 41205 18;93698 39735;93713 40110 32;95895 40125 32;95858 39840;93698 39735 18;109140 44588 1;109118 44813;109118 44918;109125 45135 1;109125 45293;109245 45412;109403 45412 1;109590 45412;109688 45428;109883 45420 1;109988 45420;110063 45285;110025 45180 1;109950 45008;109860 44948;109733 44813;109140 44588 18;109140 44753 1;109118 44978;109118 44918;109125 45135 1;109125 45293;109245 45412;109403 45412 1;109590 45412;109688 45428;109883 45420 1;109988 45420;110063 45285;110025 45180 1;109950 45008;109980 45053;109852 44918;106343 43290 1;106320 43425;106350 43537;106470 43598 1;107220 44025;107580 44295;108390 44618 1;108547 44685;108750 44655;108795 44483 1;108803 44430;108712 44460;108667 44430 1;108345 44258;108165 44198;107828 44055 1;107663 43995;107587 43950;107438 43868;106343 43290 18;106335 43380 1;106335 43478;106373 43553;106470 43598 1;107220 44025;107580 44295;108390 44618 1;108503 44670;108637 44670;108720 44603;108488 44633;109148 44948 32;109125 44595 32;108727 44430;108488 44633 18;109635 46050 1;109792 45863;109935 45803;110190 45743 1;110422 45698;110535 45593;110685 45398 1;110768 45293;110753 45203;110753 45060 1;110745 45015;110685 45037;110640 45023 1;110310 44955;110145 44925;109823 44835;109868 44955 33;109928 45015;109980 45082;110025 45180 1;110063 45285;109988 45420;109883 45420 1;109688 45428;109590 45412;109403 45412 1;109343 45412;109297 45405;109253 45375 32;109020 45435 33;108840 45405;108675 45330;108533 45330 1;108323 45338;108150 45495;107962 45495 1;107587 45503;107190 45398;106695 45398 1;106553 45398;106470 45338;106387 45225 1;106305 45135;106350 45113;106320 44993 1;106283 44873;106005 44873;105983 44993 1;105945 45173;105968 45383;105983 45563 1;105990 45728;106073 45855;106238 45870 1;106538 45915;106688 45923;106995 45945 1;107243 45968;107393 46080;107520 46298 32;107805 46268;109635 46050 18;110378 45660 1;110903 45638;111165 45593;111698 45540 1;111825 45533;112080 45540;112005 45435 1;111900 45308;111803 45270;111645 45233 1;111262 45150;111083 45060;110700 45023;110378 45660 18;105225 46245;106380 46313 32;107520 46298 33;107393 46080;107243 45968;106995 45945 1;106688 45923;106538 45915;106238 45870 1;106073 45855;105990 45728;105983 45563 1;105968 45383;105960 45285;105998 45105 1;106020 44985;106283 44985;106320 45105 1;106350 45225;106305 45308;106387 45398 1;106470 45510;106575 45495;106718 45495 1;107212 45495;107587 45503;107962 45495 1;108150 45495;108323 45338;108533 45330 1;108675 45330;108840 45405;109020 45435 32;109110 45412 32;109193 45330 33;109148 45277;109125 45210;109125 45135 1;109118 45068;109140 44993;109140 44940 32;108698 44693 32;108593 44655 32;108525 44655 33;108480 44655;108428 44640;108390 44618 1;107633 44325;107273 44070;106620 43688 32;106575 43643 33;106283 43755;106087 43800;105825 43920 32;105675 43950 32;105180 46193;105225 46245 18;110475 43515 1;110348 43980;110303 44265;110205 44730 1;110160 44925;110393 45000;110587 45045 1;110775 45098;110873 45120;111075 45120 1;111218 45120;111405 45248;111435 45090 1;111503 44662;111585 44332;111683 43860;110475 43515 18;109148 43770;106815 41858;106417 41910 33;106515 42120;106590 42225;106733 42420 1;106883 42660;106995 42690;107273 42735 1;107498 42780;107678 42457;107917 42488 1;108172 42533;108195 42930;108458 42893 1;108660 42870;108735 42848;108833 42818 32;109058 42750 1;109223 42698;109223 42525;109238 42345 1;109245 42113;109058 42023;108870 41880;106815 41858 18;103305 42098 33;103583 42412;104280 42615;104955 42720 1;104977 42728;105000 42735;105023 42735 32;105180 42683 1;104948 42308;104723 42203;104430 41873;103305 42098 50;105458 41880 1;105578 42180;105533 42375;105720 42638 1;105803 42773;105900 42832;106058 42840 1;106462 42870;106635 43050;107025 43193 1;107625 43433;107873 43703;108458 43980 1;108615 44063;108840 43868;108885 43695 1;108975 43298;108990 43095;109118 42698 1;109163 42548;108878 42660;108727 42630 1;107783 42465;107348 42233;106455 41918;105458 41880 18;109448 41498;109477 40680 32;107775 40620 32;107730 41588;109448 41498 18;97508 40680 1;97433 40418;97395 40283;97297 40020 1;97230 39863;97020 39900;96870 39983 1;96698 40080;96428 40275;96593 40373;97508 40680 18;99803 41287 1;99998 41310;100087 41363;100290 41385 1;101340 41535;101843 41820;102915 41835 1;103035 41843;103238 41835;103200 41715 1;103073 41332;102795 41018;102510 40793 1;102315 40658;102128 40673;101948 40620 1;101355 40440;100800 40590;100073 40418 1;99863 40373;99750 40410;99540 40388 1;99180 40358;99023 40223;98670 40223 1;98363 40223;98325 40545;98167 40800;99803 41287 18;106852 41565 1;106845 41310;106778 41183;106665 40950 1;106613 40853;106590 40748;106485 40740 1;106290 40733;106200 40725;106012 40725 1;105765 40725;105630 40635;105413 40718 1;105308 40763;105285 40845;105270 40950 1;105240 41152;105255 41258;105248 41460;106852 41565 18;106635 41543;107797 41550 32;107843 40650 32;106485 40703;106635 41543 18;102278 40650;103148 41760 32;104348 41460 32;105278 41445 32;105390 40718 32;103215 40740 32;102683 40703;102278 40650 18;103598 42698 1;103628 42615;103620 42563;103650 42465 1;103695 42308;103485 42270;103335 42203 1;103012 42068;102803 42105;102465 42158 1;102240 42195;102135 42255;101925 42308;103598 42698 18;117540 45810 1;114900 45548;113212 45443;110587 44902 1;109238 44633;107730 43890;107063 43560 1;106095 43065;106170 42923;104955 42720 1;104220 42600;103455 42368;103245 42000;119198 43943;124530 43718;103035 45832 1;103538 45908;103913 45968;104550 45975 1;105608 45990;106125 45803;107167 45555 1;108075 45345;108518 45000;109470 45015 1;110520 45030;110985 44580;112005 44273 1;112890 44010;113318 43815;114210 43553 1;115095 43290;115568 43170;116505 43155 1;117450 43140;117930 43125;118868 42930 1;119850 42743;120315 42533;121245 42135 1;122310 41670;123068 41543;123690 40553 1;124073 39938;124530 39645;124545 38925;124538 38925 1;124530 38310;124462 37845;123968 37613 1;123225 37290;122685 37365;122145 36773 1;121575 36165;121545 35670;121245 34890 1;121118 34590;121042 34328;120938 34095;110880 45870 1;111315 45638;111690 45428;112305 45233 1;113955 44700;114788 44370;116505 44093 1;117780 43890;118440 43905;119685 43553 1;120750 43260;121260 43013;122288 42593 1;123248 42218;123818 41933;124538 41453;124545 37350 1;124365 37268;124170 37178;123945 37050 1;123210 36660;122580 36503;122348 35693 1;122198 35183;122190 34912;121988 34410 1;121935 34298;121883 34193;121830 34095;113865 46080 1;114053 45975;114248 45855;114495 45705 1;115215 45285;115590 45000;116415 44820 1;117465 44603;118020 44550;119100 44423 1;121328 44160;122288 43695;124448 42795;124538 42773;124545 36488 1;123570 36015;122925 35468;122648 34350 1;122618 34260;122587 34178;122558 34103;74145 38430 1;73950 38055;73710 37950;73350 37725 1;73073 37568;72870 37613;72563 37650 1;72315 37688;72135 37478;72128 37230 1;72105 37058;72053 37043;71813 37035 1;71655 37035;71588 37140;71512 37268 1;71445 37373;71378 37463;71265 37433 1;71078 37388;70980 37395;70808 37335 1;70665 37298;70305 37268;70283 37628 1;70260 37950;70538 38078;70703 38070;74145 38430 18;70770 38093;70538 37148 32;69503 37890;70770 38093 18;70335 37748 1;70313 37703;70298 37658;70305 37605 1;70313 37463;70560 37193;70808 37335 1;70965 37418;71078 37388;71265 37433 1;71378 37463;71445 37373;71512 37268 1;71588 37140;71655 37035;71813 37035 1;72053 37043;72105 37058;72128 37230 1;72135 37478;72315 37688;72563 37650 1;72870 37613;73073 37568;73350 37725 1;73665 37928;73890 38033;74078 38318;74310 33945 1;73943 34118;73718 34238;73395 34530 1;72367 35460;71655 36075;70838 36750 1;70748 36825;70650 36900;70538 36983;70448 37125;70560 37320 32;70688 37335 33;70725 37328;70762 37328;70808 37335 1;70980 37395;71078 37388;71265 37433 1;71378 37463;71445 37373;71512 37268 1;71588 37140;71655 37035;71813 37035 1;72053 37043;72105 37058;72128 37230 1;72135 37478;72315 37688;72563 37650 1;72870 37613;73073 37568;73350 37725 1;73643 37912;73860 38018;74040 38265 32;74175 38483 32;76815 38385 32;76913 38108 33;77033 37515;77288 37140;77430 36443 1;77610 35483;77790 34740;77850 33960;74310 33960;74310 33945 18;77558 35498 1;77738 35527;77835 35535;78023 35573 1;78158 35603;78315 35603;78420 35498 1;78563 35355;78600 35198;78570 34988 1;78503 34628;78593 34545;78450 34200 1;78413 34118;78233 34103;78143 34095 1;78023 34095;77948 34103;77835 34103;77558 35498 18;79913 33975 1;79875 34027;79838 34080;79800 34140 1;79718 34260;79545 34230;79448 34133 1;79328 34035;79238 34020;79133 33968;77820 33968;77813 34125 1;78045 34118;78038 34103;78120 34103 1;78210 34110;78338 34155;78375 34238 1;78518 34582;78503 34628;78570 34988 1;78600 35198;78548 35340;78405 35483 1;78323 35565;78233 35580;78135 35565 32;77918 35543 32;77483 35408 1;77423 35408;77385 35415;77355 35453;77355 35828 1;77963 35888;78262 35948;78878 35978 1;79088 35993;79215 35970;79410 36060 1;79545 36128;79635 36203;79658 36353 1;79695 36705;79725 36878;79740 37223 1;79740 37380;79852 37568;80003 37508 1;80205 37440;80273 37305;80378 37110 1;80505 36863;80565 36735;80685 36473 1;80753 36308;80865 36263;81015 36158 1;81218 36015;81330 35963;81548 35828 1;81690 35745;81893 35707;81968 35858 1;82043 36015;82005 36113;82088 36263 1;82125 36360;82193 36510;82290 36465 1;82425 36412;82583 36270;82583 36113 1;82583 35902;82500 35805;82418 35603 1;82313 35370;82230 35250;82245 34988 1;82245 34920;82193 34868;82125 34860 1;81727 34838;81525 34793;81135 34777 1;80985 34777;80865 34815;80723 34793;80573 34763 33;80400 34680;80348 34673;80250 34598 1;80130 34523;80145 34245;80242 34140 1;80280 34095;80310 34043;80340 33998 32;80288 33975;79913 33975 18;81360 34770 1;81352 34808;81383 34838;81420 34838 1;81600 34868;81698 34883;81893 34868 1;81960 34868;81983 34823;82035 34770 1;82117 34688;82125 34568;82058 34463 1;81938 34298;81727 34373;81548 34463 1;81413 34537;81390 34650;81383 34800;81360 34770 18;83250 35798 1;83400 35933;83595 35963;83670 35873 1;83745 35790;83693 35603;83543 35468 33;83393 35340;83198 35303;83130 35393 1;83048 35483;83100 35670;83250 35798 18;83063 33983 1;83108 34058;83145 34140;83168 34253 1;83168 34298;83175 34373;83220 34350;83258 34365 1;83363 34305;83468 34275;83573 34343 1;83633 34388;83708 34425;83760 34365 1;83828 34290;83805 34185;83738 34103 1;83693 34058;83648 34013;83602 33975;83055 33983;83063 33983 18;81765 33983;81908 34380 1;81968 34388;82012 34418;82058 34463 1;82125 34568;82117 34688;82035 34770 32;81953 34853 33;82005 34860;82065 34860;82125 34860 32;82230 34890 1;82275 34725;82395 34688;82530 34575 1;82658 34470;82762 34455;82935 34470 1;83108 34493;83063 34703;83175 34838 1;83235 34920;83333 34912;83423 34860 1;83528 34793;83355 34673;83265 34575 1;83205 34515;83168 34448;83213 34373;83258 34365 32;83220 34350 1;83175 34373;83168 34298;83168 34253 1;83145 34140;83108 34058;83070 33975;81765 33983 18;83625 36870 1;83588 36968;83483 37043;83573 37088 1;83753 37200;83910 37260;84090 37373 1;84180 37440;84315 37455;84398 37373 1;84540 37238;84488 37095;84593 36915 1;84713 36705;84840 36608;85080 36548 1;85275 36510;85463 36540;85538 36345 1;85590 36195;85628 36113;85650 35948 1;85658 35850;85628 35775;85553 35715 1;85477 35670;85425 35670;85343 35685 1;84990 35768;84803 35843;84450 35783 1;84308 35760;84165 35730;84098 35850 1;83873 36233;83783 36435;83625 36840;83625 36870 18;83520 37035 1;83453 37185;83415 37268;83378 37418 1;83348 37515;83430 37643;83528 37628 1;83760 37598;83895 37620;84113 37515 1;84173 37485;84240 37463;84300 37410;83520 37035 18;84367 37365 1;84863 37283;85268 37343;85560 36923 1;85643 36803;85650 36683;85583 36540 1;85538 36473;85463 36473;85387 36473 1;85095 36495;84915 36510;84705 36698 1;84495 36885;84465 37050;84367 37298;84367 37365 18;81278 35955 1;81383 36480;81518 36713;81727 37200 1;81773 37320;81900 37373;82012 37313 1;82253 37193;82365 37118;82598 36960 1;82718 36878;82830 36863;82965 36923 1;83168 37020;83408 37043;83617 37133 1;83640 37148;83595 37215;83648 37035 1;83753 36503;83963 36428;84113 35895 1;84120 35850;84090 35828;84075 35783 1;83963 35580;83880 35385;83648 35385 1;83512 35385;83445 35408;83318 35408 1;83280 35408;83235 35400;83242 35363 1;83280 35168;83295 35055;83242 34860 1;83175 34658;83137 34478;82935 34418 1;82658 34350;82477 34493;82290 34695;81278 35955 18;88395 35685 1;88170 35730;88050 35895;88035 36113 1;87998 36450;87983 36615;87960 36945 1;87945 37103;88012 37193;88125 37290 1;88215 37380;88283 37388;88395 37440;88395 35685 18;88931 37484;89374 37484 32;89374 36689 32;88931 36689 32;88931 37484 18;89900 36396;90252 35946 32;89712 35533 32;89367 35983 32;89900 36396 18;84262 37410 1;84675 37658;84908 37740;85365 37912 1;85477 37957;85613 37928;85650 37808 1;85748 37463;85778 37275;85845 36915 1;85852 36840;85740 36758;85680 36803;85598 36848 33;85590 36870;85575 36900;85560 36923 1;85275 37328;84893 37290;84420 37358 32;84352 37320;84262 37410 18;83617 33983;83738 34103 1;83805 34185;83828 34290;83760 34365 1;83708 34425;83633 34388;83573 34343 1;83468 34275;83363 34305;83258 34365;83220 34350 32;83190 34448 33;83190 34493;83220 34537;83265 34575 1;83355 34673;83528 34793;83423 34860 1;83378 34890;83340 34898;83303 34905 32;83242 34860 33;83288 35040;83280 35145;83250 35303 32;83220 35355 33;83273 35348;83340 35363;83408 35385 32;83445 35400 33;83505 35400;83565 35385;83648 35385 1;83880 35385;83963 35580;84075 35783 32;84098 35850 33;84165 35730;84308 35760;84450 35783 1;84803 35843;84990 35768;85343 35685 1;85425 35670;85477 35670;85553 35715 1;85628 35775;85658 35850;85650 35948 1;85628 36113;85590 36195;85538 36345 1;85523 36383;85508 36405;85492 36428 32;85455 36480 33;85500 36480;85545 36495;85583 36540 1;85613 36623;85628 36690;85620 36758 32;85770 36780 1;85943 36638;86048 36510;86137 36353 32;86288 36075 1;86325 36008;86280 35933;86220 35880 1;85838 35573;85673 35378;85410 34965 1;85343 34868;85485 34733;85605 34748 1;86003 34815;86175 35033;86565 35168 1;86678 35213;86790 35040;86813 34912 1;86835 34770;86730 34635;86850 34537 1;86925 34478;87000 34425;87068 34380;86678 33998;83617 33983 18;88193 33998 1;88185 34058;88178 34118;88163 34193 1;88133 34328;88133 34448;88245 34523 1;88358 34605;88425 34628;88545 34703;88665 33998;88193 33998 18;86303 36000 1;86400 36090;86558 36150;86625 36037 1;86790 35753;86768 35662;86880 35340 1;86918 35228;86783 35220;86625 35152;86565 35108 33;86175 34973;86003 34815;85605 34748 1;85485 34733;85343 34868;85410 34965 1;85673 35378;85838 35573;86220 35880 1;86235 35902;86250 35918;86265 35940 32;86303 36000 18;86498 33998;86933 34455 1;87030 34402;87203 34313;87255 34207;87285 34125 33;87285 34080;87285 34035;87270 33990;86498 33998 18;87210 33998 1;87293 34050;87428 34073;87473 33990;87210 33998 18;87465 34005;87345 34043 32;87285 34043 33;87285 34073;87285 34103;87285 34125 32;87255 34207 1;87218 34283;87165 34313;87105 34335 32;87023 34410 33;86970 34448;86910 34493;86850 34537 1;86730 34635;86835 34770;86813 34912 1;86798 34988;86760 35063;86708 35115 32;86625 35152 33;86783 35220;86918 35228;86880 35340 1;86768 35662;86790 35753;86625 36037 1;86558 36150;86400 36090;86303 36000 32;86288 36075 32;86137 36353 33;86048 36510;85943 36638;85770 36780 33;85793 36810;85845 36870;85845 36915 1;85838 36938;85838 36960;85830 36975 32;85823 37020 33;85770 37320;85733 37500;85650 37808 1;85613 37928;85477 37957;85365 37912 1;84930 37755;84698 37673;84323 37455 32;84240 37455 33;84195 37478;84150 37500;84113 37515 1;84098 37523;84090 37530;84075 37530 32;84023 37553 33;83850 37620;83723 37605;83528 37628 1;83430 37643;83393 37508;83423 37410 1;83445 37313;83468 37253;83498 37178 32;83505 37095 33;83325 37035;83130 37005;82965 36923 1;82920 36908;82890 36900;82852 36893 32;82800 36870 32;82290 36465 33;82193 36510;82125 36360;82088 36263 1;82005 36113;82043 36015;81968 35858 1;81893 35707;81690 35745;81548 35828 1;81330 35963;81218 36015;81015 36158 1;80865 36263;80753 36308;80685 36473 1;80565 36735;80505 36863;80378 37110 1;80273 37305;80205 37440;80003 37508 1;79852 37568;79740 37380;79740 37223 1;79725 36878;79695 36705;79658 36353 1;79635 36203;79545 36128;79410 36060 1;79215 35970;79088 35993;78878 35978 1;78360 35955;78068 35910;77625 35858 32;77550 35858 32;77483 36120 32;76898 38453 32;85230 39015;85650 38378 32;86025 37695 32;86288 37200;87180 37365;88395 37440 33;88283 37388;88215 37380;88125 37290 1;88095 37275;88073 37253;88058 37230 32;88020 37193 33;87975 37125;87945 37050;87960 36945 1;87983 36615;87998 36450;88035 36113 1;88043 35918;88148 35760;88343 35700 32;88433 35662 32;88598 34695 32;88448 34650 33;88380 34613;88320 34582;88245 34523 1;88133 34448;88133 34328;88163 34193 1;88178 34118;88185 34050;88193 33990;87450 33998;87465 34005 18;82245 36488;82800 36900 32;82875 36900 33;82905 36900;82935 36915;82965 36923 1;83115 36998;83295 37035;83460 37080 32;83535 37043 33;83535 36998;83595 36938;83625 36870;83625 36840 1;83783 36435;83873 36233;84098 35850 32;84075 35783 33;83963 35580;83880 35385;83648 35385 1;83573 35385;83520 35393;83468 35400 32;83543 35468 33;83693 35603;83745 35790;83670 35873 1;83602 35955;83453 35940;83318 35858 32;83250 35798 33;83100 35670;83048 35483;83130 35393 1;83145 35370;83175 35355;83213 35348 32;83250 35303 33;83280 35145;83288 35040;83242 34860 32;83175 34838 33;83063 34703;83108 34493;82935 34470 1;82762 34455;82658 34470;82530 34575 1;82395 34688;82275 34725;82230 34890 32;82245 34988 33;82230 35250;82313 35370;82418 35603 1;82500 35805;82583 35902;82583 36113 1;82583 36270;82425 36412;82290 36465;82245 36488 18;69352 34590 1;69608 34628;69758 34748;69998 34635 1;70110 34582;70133 34463;70110 34328 1;70073 34178;69990 34095;69848 34035 1;69750 34005;69690 33975;69600 33998 1;69488 34035;69428 34058;69330 34088;69352 34590 18;69233 37740 1;69285 37710;69345 37673;69413 37635 1;69525 37568;69727 37395;69600 37350;69233 37290;69240 37740;69233 37740 18;69248 36248;69555 36713 32;69975 37373 32;70208 37230 33;70448 37058;70673 36885;70838 36750 1;71655 36075;72367 35460;73395 34530 1;73718 34238;73943 34125;74295 33953;69255 33938;69248 36248 18;82305 36465 33;82470 36375;82583 36248;82583 36113 1;82583 35902;82500 35805;82418 35603 1;82313 35370;82230 35250;82245 34988 1;82245 34965;82230 34935;82215 34912;82253 34823 1;82313 34718;82410 34673;82530 34575 1;82658 34470;82762 34455;82935 34470 1;83108 34493;83063 34703;83175 34838 1;83183 34860;83198 34868;83265 34973 1;83288 35108;83265 35213;83213 35348 1;83175 35355;83145 35370;83130 35393 1;83048 35483;83100 35670;83250 35798;83318 35858 1;83453 35940;83602 35955;83670 35873 1;83745 35790;83693 35603;83543 35468;83468 35400 1;83520 35393;83573 35385;83648 35385 1;83880 35385;83963 35580;84075 35783;84098 35850 33;83873 36233;83783 36435;83625 36840;83625 36870 1;83595 36938;83535 36998;83535 37043;80123 33975;80235 34118 1;80378 33953;80558 33960;80783 33990 1;80977 34027;81000 34200;81135 34343 1;81218 34448;81367 34380;81465 34283 1;81548 34207;81668 34103;81585 34013;81518 33968;80123 33975 18;81893 34373;81608 34095 33;81600 34162;81518 34230;81465 34283 1;81367 34380;81218 34448;81135 34343 1;81000 34200;80977 34027;80783 33990 1;80558 33960;80378 33953;80235 34118 32;80213 34178 33;80137 34298;80137 34530;80250 34598 1;80348 34673;80400 34680;80573 34763 32;80723 34793 1;80865 34815;80985 34777;81135 34777 1;81210 34785;81293 34808;81390 34777 33;81398 34650;81420 34537;81548 34463 1;81630 34425;81727 34380;81810 34373;81893 34373 18;79125 33968 1;79238 34020;79328 34035;79448 34133 1;79545 34230;79718 34260;79800 34140 1;79838 34080;79875 34027;79913 33968;79117 33975;79125 33968 18;81540 33990;81585 34013 1;81608 34043;81615 34065;81608 34095 32;81645 34133 32;81893 34373 32;81938 34388;81855 33975;81540 33983;81540 33990 18;95670 46875 1;95588 46770;95550 46710;95475 46598 1;95438 46568;95400 46545;95363 46553 1;95318 46553;95280 46568;95250 46598 1;95130 46710;95025 46733;94973 46875 1;94943 46943;94935 47003;94935 47048 1;94935 47115;94943 47175;95003 47220 1;95063 47303;95085 47363;95183 47400 1;95288 47460;95378 47430;95498 47370 1;95573 47332;95617 47295;95700 47235 1;95730 47220;95753 47183;95753 47138 1;95760 47108;95745 47070;95738 47018 1;95708 46973;95693 46943;95670 46890;99667 53460;99720 52590 32;99000 52523 32;98977 52650 32;98977 52808 1;98955 52965;98933 53108;98910 53302;98835 53378 32;98933 53460;99667 53460 18;100313 75218 1;100283 74850;100215 74670;100170 74295 1;100080 73658;101325 72360;101813 72060;107265 71753 32;108390 67440;101520 67823;103268 65910;97365 37207;96413 35798;113805 35933;115455 35190;115335 36938;116745 38303;118477 35010;118868 76673 1;118118 75915;117443 75473;117480 74408 1;117503 73643;117818 73238;118387 72713 1;119093 72060;119415 71588;120337 71288;106417 70725 1;106515 70793;106628 70830;106718 70748 1;106868 70620;106710 70433;106620 70253 1;106373 69795;106605 69473;106553 68955 1;106523 68730;106477 68602;106320 68430 1;105998 68108;105840 67950;105540 67605 1;105375 67425;105075 67688;105023 67920 1;104940 68273;104985 68475;105113 68805 1;105285 69278;105383 69503;105608 69945 1;105803 70350;106050 70455;106410 70725;106417 70725 18;108352 67560;108398 67463 32;110212 65933 32;110265 65843 1;110183 65783;110160 65730;110078 65670 1;110025 65640;109973 65602;109935 65640 1;109733 65828;109628 65918;109433 66098 1;108975 66525;108683 66653;108143 66945 1;108015 67020;107917 67170;108015 67275 1;108105 67380;108165 67418;108270 67508;108352 67560 18;99090 70635 1;99780 70628;100148 70598;100815 70380 1;100973 70328;101063 70238;101108 70065 1;101243 69525;101438 69262;101445 68700 1;101445 68408;101363 68250;101205 67995 1;101123 67875;101070 67815;101063 67665 1;101055 67575;100792 67553;100830 67635 1;100898 67830;100883 67943;100958 68130 1;101025 68318;101137 68445;101040 68610 1;100883 68873;100800 69038;100530 69173 1;100238 69323;100058 69345;99743 69330 1;99450 69323;99300 69315;99015 69293;99090 70635 18;98880 67477 1;99255 67553;99578 67658;99848 67373 1;100042 67163;100155 67073;100358 66863 1;100455 66758;100688 66810;100718 66953 1;100770 67215;100718 67365;100815 67605 1;100837 67688;100980 67680;101025 67605 1;101153 67403;101355 67178;101565 67313 1;101843 67508;102053 67605;102383 67515 1;102608 67455;102743 67313;102765 67073 1;102788 66803;102727 66630;102555 66413 1;102405 66240;102405 66090;102420 65858 1;102428 65625;102578 65453;102818 65415 1;103268 65363;103665 65340;103920 65723 1;104093 66000;104250 66120;104310 66435 1;104348 66660;104438 66915;104663 66878 1;104880 66848;105030 66720;105075 66495 1;105120 66210;105352 65985;105645 66030 1;106012 66098;106410 66120;106553 65768 1;106703 65393;106725 64957;106373 64762 1;105262 64133;104670 63608;103613 62970 1;103350 62813;103110 62828;103178 62528 1;103365 61695;103395 61740;103590 60900 1;103605 60832;103568 60750;103500 60750 1;103260 60750;103148 60690;102915 60690 1;102840 60690;102795 60735;102773 60795 1;102637 61148;102547 61418;102195 61515 1;100808 61912;100163 62242;98775 62603 1;98573 62655;98348 62662;98288 62468 1;97995 61515;97800 61170;97305 60720 1;97245 60668;97173 60451;97098 60451 1;96896 60458;96861 60334;96831 60521 1;96741 60994;96870 61043;97073 61470 1;97395 62175;97417 62595;97477 63367;97568 63383 33;97703 63360;97845 63375;98010 63427 1;98153 63495;98205 63600;98265 63742 32;98265 63795 1;98355 64095;98385 64245;98490 64537 1;98558 64755;98498 64973;98303 65063 1;98235 65093;98205 65160;98235 65220 1;98422 65685;98580 65887;98783 66345;98880 67477 18;102893 60750;100808 60826 32;98828 60262 32;97425 60255 32;98212 62775 32;98633 62887 32;102390 61733 32;102855 61020;102893 60750 18;98903 67500 1;99225 67553;99428 67620;99727 67477 1;99915 67395;100005 67260;100028 67043 1;100080 66518;99900 66255;99818 65723 1;99705 65033;99608 64635;99150 64095 1;98940 63863;98715 63795;98408 63832 1;98115 63878;97958 63855;97688 63960;97733 64117 32;98828 66390;98850 67117 32;98903 67500 18;104865 66503;108323 67425 32;109028 64950 32;105900 62873 32;106433 61260 32;105150 61373 32;104633 61207 32;103500 60795 32;102690 63427 32;104917 64852;104865 66503 18;105150 66270 1;105120 66413;105083 66593;105225 66615 1;106448 66878;107047 67065;108248 67418 1;108300 67440;108360 67410;108383 67350 1;108615 66435;108720 65977;109005 65070 1;109028 64995;109028 64920;108960 64867 1;107790 64088;107235 63653;106020 62955 1;105953 62925;105885 62873;105915 62798 1;106095 62280;106163 62010;106387 61500 1;106417 61418;106305 61358;106215 61350 1;105780 61335;105555 61433;105128 61350 1;104925 61320;104820 61298;104633 61223 1;104175 61065;103995 60840;103523 60773 1;103440 60765;103350 60765;103343 60840 1;103200 61658;103283 61485;103110 62287 1;103020 62677;103403 62903;103748 63105 1;104318 63457;104738 63720;105420 64155 1;105637 64290;105637 64793;105547 65033 1;105352 65520;105300 65775;105150 66270 18;90503 50235;92340 50512;103223 53100 1;102600 53100;102292 53123;101678 53175;101633 53175 33;101633 53205;101625 53235;101625 53265 1;101528 53707;101445 53963;101303 54293 32;101265 54323 1;102248 54240;102735 54165;103710 53992;103223 53100 18;113940 41393;113933 41850 32;114735 41850 32;114743 41400 32;113940 41393 18;118080 37358;116430 41678;116512 41618 32;118500 40335 32;118462 39060 32;118433 38865 1;118028 38633;117803 38438;117667 37995 1;117375 37073;117540 36480;117922 35588;117983 35513 33;117818 35332;117630 35213;117375 35040 1;117105 34875;116903 34838;116655 34755 32;116385 34770 33;115643 35573;115403 36008;114825 36930 1;114623 37253;114547 37613;114533 37995 32;114533 38183 32;114585 38393 1;114968 38385;115148 38543;115493 38723 1;116055 39030;116430 39390;116430 40027 1;116422 40695;116363 41018;116318 41678;116430 41678 18;114727 37230 1;114480 37200;114337 37253;114120 37358 1;113775 37530;113783 37853;113745 38220 1;113738 38280;113805 38287;113865 38280 1;114105 38273;114225 38348;114473 38370;114727 37230 18;115943 35348 1;115268 35348;114930 35565;114352 35895 1;114210 35978;114233 36150;114308 36285 1;114473 36600;114570 36750;114788 37027;115943 35348 18;111968 34073;112058 34148 1;112440 34388;112658 34455;113063 34665 1;113167 34725;113363 34703;113363 34575 1;113363 34395;113378 34215;113318 34073;111968 34073 18;124545 37508;122010 38648 32;118598 37140 32;118508 40358 32;116333 41738;116265 42375;115868 42353 32;115837 41738 32;114420 40470 32;114075 38340 32;109523 38348 32;109448 43155 32;112613 44033 32;119220 43943 32;124530 43695;124553 37508;124545 37508 18;118823 34080 1;118920 34230;119003 34298;119153 34410 1;119265 34508;119445 34485;119528 34350 1;119587 34245;119640 34170;119685 34088;118815 34095;118823 34080 18;120653 34103 1;120750 34193;120848 34148;120953 34095;120667 34103;120653 34103 18;123465 34110 1;123585 34170;123712 34253;123848 34350 1;123990 34485;124238 34568;124433 34500 1;124477 34485;124523 34478;124560 34470;124568 34110 32;123465 34110 18;119288 35280;119813 34095;114990 34073 1;115417 34238;115875 34418;116415 34650 1;116580 34733;116723 34777;116858 34815 32;116903 34658 1;117045 34433;117158 34253;117262 34080;114990 34088;114990 34073 18;97598 39953 32;99398 40185 1;99653 40223;99893 40245;100118 40275 32;100193 40162 33;99727 39803;99480 39630;98970 39330 1;98565 39098;98303 38948;98085 38595 32;98003 38483 1;97875 39045;97725 39308;97508 39832;97598 39953 50;96098 36323;96158 36930 32;97223 36323 33;97065 35783;96975 35250;96998 34605 32;96188 34793;96098 36323 18;97028 34027 1;96795 35790;97380 36728;97988 38415 1;98227 38895;98505 39060;98970 39330 1;99480 39630;99727 39803;100193 40162;102675 40402;102750 40733;103163 40748;106050 40763;106500 40740;109470 40553;109530 38370;112365 38235 1;112245 37103;112448 36510;112808 35423 1;112845 35295;112792 35175;112672 35115 1;111998 34815;111630 34703;111000 34320 1;110843 34230;110700 34148;110565 34065;97020 34027;97028 34027 18;107258 40433 1;107512 40260;107640 40148;107970 40148 1;108255 40148;108473 40207;108645 40440;107258 40433 18;96765 34020 1;96637 35100;96743 36075;97140 37268 1;97455 38243;97665 38655;98348 39270;88755 34005;88628 34755 32;88538 35287;88508 36630 32;88463 39450 32;95850 39795 32;96165 39255;95460 37560;95438 36923 32;95400 35513;95595 34020;88755 34005 18;117540 74992 1;117637 74873;117533 74393;117630 74265 1;119033 72435;120172 72390;122137 71633 1;123060 71288;123705 71033;124448 70613;120113 71183 1;121343 70762;122333 71168;123225 70193;108510 40305 33;108360 40185;108188 40148;107970 40148 1;107715 40148;107580 40215;107415 40328;96930 44738 1;97740 44655;98258 44745;99165 44655 1;100215 44550;100755 44483;101805 44595 1;102810 44715;103320 44865;104325 44790 1;105248 44745;105727 44670;106590 44310 1;107595 43890;108180 43875;109245 43575 1;110227 43313;110775 43402;111750 43073 1;112868 42705;113445 42563;114570 42135 1;115440 41805;115890 41610;116828 41535 1;118028 41430;118620 41190;119828 41190 1;120885 41190;121417 40823;122310 40230 1;122708 39975;122940 39803;123165 39375 1;123375 38985;123337 38460;122925 38273 1;122288 37995;121980 37815;121305 37613 1;120915 37500;120727 37260;120630 36870 1;120435 36210;120450 35850;120210 35213 1;120128 35010;120038 34853;119933 34710;90105 44213 1;90345 44145;90593 44055;90885 43935 1;91688 43605;92025 43260;92887 43095 1;93727 42930;94170 42983;95025 42953 1;96578 42915;97358 42953;98910 42810 1;100350 42690;101085 42623;102510 42293 1;103515 42060;104010 41790;105045 41730 1;106665 41655;107475 41655;109110 41550 1;109898 41513;110205 41085;110925 40733 1;111765 40335;112320 40313;113047 39713 1;113310 39503;113408 39315;113468 38970 1;113618 38055;113468 37523;113850 36652 1;114158 35940;114345 35580;114870 34995 1;114915 34935;114990 34943;115065 34890 1;115245 34770;115050 34380;114825 34395 1;114345 34425;114098 34380;113625 34350 1;113265 34335;113033 34230;112800 34073;92753 44152 1;93060 44078;93383 44033;93810 44010 1;94598 43995;94988 43853;95790 43853 1;97515 43853;98385 44010;100125 43995 1;101400 43980;102000 43575;103260 43343 1;104505 43125;105105 42825;106380 42743 1;107648 42675;108300 42900;109575 42743 1;110160 42675;110408 42450;110977 42263 1;111675 42045;112140 42210;112778 41820 1;113288 41513;113528 41325;113977 40905 1;114435 40485;114908 40635;115538 40703 1;116348 40800;116768 40853;117578 40703 1;118230 40582;118635 40260;118860 39623 1;119145 38745;119205 38273;119378 37343 1;119475 36743;119610 36285;119205 35813 1;119137 35745;119070 35678;119010 35618;83528 41888 1;83828 41603;84270 41430;84727 41152 1;85380 40763;85620 40425;86295 40065 1;87248 39570;87900 39773;88980 39705 1;90458 39623;91215 39713;92700 39465 1;94005 39240;94643 39218;95820 38588 1;96518 38228;95715 37493;95753 36698 1;95798 35662;95760 35513;95865 34545 1;95887 34328;95903 34155;95910 34020;81375 40148 1;81495 40027;81630 39893;81788 39750 1;82800 38820;83438 38475;84690 37875 1;85800 37343;86445 37170;87390 36353 1;88155 35693;88875 35332;88905 34313 1;88905 34200;88898 34095;88890 33998;76305 38633 1;76508 38363;76785 38123;77108 37815 1;77760 37185;78225 37005;78810 36293 1;79320 35662;79575 35213;79568 34395 1;79560 34245;79553 34103;79538 33968;103898 66593 1;104055 66788;104078 66818;104295 67065 1;104685 67545;105120 67605;105735 67620 1;106560 67665;106935 67283;107655 66863 1;108285 66495;108630 66195;109365 66195 1;110400 66195;110865 66660;111765 67170 1;112350 67515;112920 68003;113408 67530 1;113925 67043;113828 66443;113648 65730 1;113325 64590;112875 64110;112208 63135 1;111375 61943;110340 62025;109065 61313 1;107520 60465;106650 60165;105330 58995 1;105053 58762;104805 58530;104542 58328;69173 56070 1;69390 56018;69623 55973;69908 55935 1;70538 55860;70845 55680;71490 55710 1;72120 55755;72420 55920;73050 56070 1;73830 56273;74175 56490;74925 56790 1;75870 57180;76545 57953;76305 58935 1;76058 59955;75885 60443;75645 61455 1;75458 62220;75518 62685;75810 63412 1;75960 63802;75990 64125;76365 64290 1;76995 64590;77355 64673;78045 64830 1;78735 65010;79230 65040;79665 65610 1;79958 66000;80160 66233;80625 66352 1;81030 66465;81225 66585;81645 66555 1;82238 66525;82568 66330;82988 65895 1;83460 65393;83918 65363;84608 65310 1;85005 65295;85215 65190;85628 65213 1;86205 65250;86475 65423;87045 65550 1;87810 65745;88215 65805;89010 65775 1;90120 65745;90668 65543;91770 65310 1;92887 65085;93518 65175;94590 64733 1;95280 64455;95730 64530;96345 64110 1;96908 63735;97221 63426;97596 62849 1;98106 62046;98370 61662;98865 60845 1;99255 60207;98985 59393;98408 58912 1;97665 58320;97200 58162;96390 57675 1;95475 57143;95115 56730;94185 56250 1;93135 55733;92550 55590;91568 54953 1;90795 54465;90405 54203;89730 53595 1;88770 52740;88148 52485;87270 51555 1;86730 50992;86580 50625;86145 49973 1;85755 49395;85530 49110;85028 48630 1;84308 47963;83970 47565;83565 46673 1;83198 45885;83190 45390;83190 44513 1;83190 43838;83078 43470;83123 42848;88515 77033 1;88898 77250;89198 77430;89730 77430 1;90240 77445;90555 77235;90870 76815 1;91148 76433;91440 76253;91448 75773 1;91448 75555;91538 75443;91530 75210 1;91500 74775;91245 74580;91290 74130 1;91328 73590;91358 73305;91605 72810 1;92145 71745;92708 71123;93885 70830 1;94380 70710;94658 70905;95130 71093 1;95438 71220;95610 71340;95948 71310 1;96465 71280;96795 71153;97125 70733 1;97800 69885;98018 69360;98625 68453 1;98835 68130;98940 67950;99165 67635 1;99308 67440;99608 67515;99765 67695 1;100215 68213;100575 68333;101085 68790 1;101715 69383;102000 69742;102705 70230 1;103297 70650;103635 70815;104348 70995 1;105225 71220;105705 71333;106628 71250 1;107227 71205;107490 70913;107985 70553 1;108547 70155;108908 69923;109605 69930 1;110445 69953;110805 70425;111428 70995 1;111945 71483;112208 71730;112605 72315 1;113070 72990;113490 73290;114285 73470 1;114968 73635;115320 73755;116025 73755 1;116580 73762;117113 73583;117653 73433;92258 51225 1;92183 51188;92100 51143;92025 51090 1;91867 51015;91748 50933;91635 50850;90975 49973 1;90623 49343;90255 49080;89625 48675 1;88635 48052;88208 47640;87308 46890 1;86565 46298;86063 45863;85845 45037 1;85778 44707;85740 44535;85740 44190;115725 36315 1;115943 35828;116198 35543;116715 35543 1;117405 35565;117735 36120;118065 36735 1;118102 36818;118140 36893;118178 36968;118178 35055 1;117960 34928;117735 34793;117488 34590 1;117233 34410;117045 34238;116865 34080;86858 68370;87218 68723 32;86723 69218 32;87023 69503 1;87435 69518;87720 69540;88095 69270 1;88125 69255;88117 69203;88163 69203 1;88373 69218;88455 69330;88658 69405;89250 68325 1;88575 68325;88238 68250;87570 68250 1;87525 68250;87473 68220;87473 68258 1;87458 68340;87413 68393;87338 68393 1;87188 68408;87120 68393;86977 68385 1;86933 68385;86887 68378;86858 68370 18;102165 68318 1;102450 68700;102720 68940;103208 69270 1;103837 69720;104220 69915;104985 70073 1;105765 70245;106230 70343;106988 70073 1;108030 69705;108450 69083;109568 69030 1;110685 68992;111285 69435;112148 70155 1;112958 70845;113160 71453;114090 71970 1;114727 72345;115125 72533;115868 72473 1;116917 72405;117727 72352;118328 71475 1;118845 70703;119258 70425;119970 69795 1;120660 69180;121058 68925;121710 68250 1;122205 67740;122235 67260;122265 66533 1;122295 65475;122070 64823;121365 64012 1;120818 63390;120578 63052;120008 62453 1;119400 61845;118928 61710;118365 61050 1;117848 60465;117525 60233;117068 59595 1;116340 58605;115808 58230;114825 57495 1;113738 56693;112995 56610;111825 55935 1;110310 55065;109417 54810;108030 53753 1;107595 53445;107438 53190;106965 52950 1;105788 52373;105398 51465;104085 51375 1;103238 51323;102825 51060;102090 50655 1;100890 50010;100358 49500;99045 49155 1;97898 48855;97350 48533;96428 47790 1;96158 47588;95948 47423;95730 47243;98520 45975 1;98355 45945;98167 45915;97973 45885 1;97620 45848;97425 45848;97095 45960 1;96563 46148;96323 46283;95798 46463 1;95475 46575;95303 46598;94973 46582 1;93908 46537;93375 46508;92318 46388;101768 46545 1;101655 46478;101633 46380;101618 46320;85950 41993 1;85808 41948;85665 41902;85470 41850 1;84960 41730;84713 41603;84293 41295 1;83963 41070;83790 40973;83468 40740;85913 42752;86526 42070 1;87306 41425;87727 41280;88785 41332 1;90090 41415;90758 41475;92048 41250 1;94035 40920;95018 40605;97050 40455 1;99390 40290;100575 40590;102930 40433 1;104550 40335;105360 39990;106808 39233 1;108165 38520;109005 38303;110047 37155 1;110865 36248;110880 35123;110393 34065;94943 47078 1;94410 47258;94035 47318;93750 47790 1;93645 47963;93653 48165;93810 48278 1;94005 48435;94260 48488;94433 48300 1;94762 47940;95033 47835;95295 47408;94943 47078 18;95010 46673 1;94538 46290;94065 45930;93405 45473 1;93165 45323;92970 45188;92775 45082;73852 57473;70102 55927 1;70073 56040;70193 56100;70305 56130 1;70425 56175;70583 56198;70620 56070 1;70688 55793;70718 55658;70793 55373 1;70823 55253;70725 55155;70613 55103 1;70477 55050;70335 55125;70283 55253;70102 55927 18;69150 64508;69158 64500 32;69150 64508 18;85298 38888 1;86010 37688;86498 36900;86992 35588;86303 36000 1;86400 36090;86558 36150;86625 36037 1;86790 35753;86768 35662;86880 35340 1;86918 35228;86783 35220;86625 35152;86535 35145 33;86145 35010;86003 34815;85605 34748 1;85485 34733;85343 34868;85410 34965 1;85673 35378;85838 35573;86220 35880 1;86235 35902;86250 35918;86265 35940 32;86303 36000 18;86895 39652 1;87240 39953;87548 39893;88005 39938 1;88185 39960;88440 40027;88463 39840 1;88500 39435;88463 39248;88455 38820 1;88455 38738;88500 38625;88418 38603 1;87975 38505;87742 38505;87300 38468 1;86805 38430;86760 39045;86663 39525;86895 39652 18;97794 60918;107123 51255 1;107633 51165;107880 51023;108308 50715 1;109058 50183;109538 50048;110220 49418 1;110340 49305;110355 49200;110393 49028;110955 50512 1;110738 50543;110648 50648;110475 50775 1;109808 51270;109470 51503;108765 51923 1;108518 52073;108488 52065;108248 52223;108630 50258 1;108420 50205;108188 50160;107925 50130 1;106935 50040;106417 50115;105488 49815 1;104490 49515;103995 49320;103050 48915 1;101955 48465;101655 47700;100538 47310 1;100425 47273;100253 47543;100058 47453 1;99878 47370;99953 47168;99840 47085 1;99428 46823;99053 46650;98663 46440 1;98505 46365;98370 46335;98243 46448 1;98100 46582;98033 46755;97845 46718 1;97650 46688;97575 46553;97500 46365 1;97455 46283;97462 46260;97395 46193;104393 52957 1;105540 52943;106178 53025;107250 52590;97462 60128 1;97493 59505;97493 59168;97508 58545 1;97508 58223;97643 58088;97718 57765 1;97950 56693;98145 56100;97913 55020;91463 56378;94425 57052 1;94568 57173;94545 57203;94733 57225 1;95025 57270;95220 57233;95468 57052 1;96413 56355;96690 55710;97118 54608 1;97178 54457;96840 54457;96705 54540 1;96195 54855;95963 55088;95385 55215 1;94920 55320;94845 55710;94538 56055 1;94223 56408;94223 56633;94425 57052 18;96465 53850 1;96428 53393;96555 53137;96398 52703 1;96352 52598;96233 52598;96120 52613 1;95835 52650;95700 52688;95423 52718 1;95265 52740;95137 52808;95123 52957 1;95070 53445;95183 53693;95190 54173 1;95190 54367;95108 54683;95295 54630 1;95835 54495;96480 54473;96488 53910;96465 53850 18;101031 60459 1;101358 60278;100718 59408;100170 59302 1;99075 59108;98535 58973;97440 58875;97493 59190 33;97485 59483;97477 59760;97462 60128 32;97635 60225 33;97650 60225;97665 60225;97688 60225 1;98685 60262;99060 60270;100178 60495 1;100275 60518;100379 60350;100469 60365 32;101031 60459 18;82598 44520 1;83033 44588;83438 44287;83505 43860 1;83573 43433;83663 43433;82838 42960 1;82200 42593;82088 43223;81945 43620 1;81675 44423;82178 44460;82598 44520 18;82950 44490;83617 44925 33;83768 44948;83895 44955;84053 44850 1;84248 44723;84450 44655;84458 44415 1;84458 44183;84315 44078;84143 43920 1;83903 43725;83715 43590;83520 43463 32;83535 43650 32;83145 44490;82950 44490 18;79725 47610 1;80183 47152;80415 46912;80895 46463 1;81195 46185;81383 46043;81540 45660 1;81750 45143;81915 44895;82020 44340;73358 41760 1;73140 41332;73133 40980;72900 40553 1;72803 40388;72630 40748;72623 40935 1;72608 41138;72645 41243;72637 41438 1;72623 41662;72765 41835;72623 42000 1;72038 42675;71708 42983;71145 43665 1;71040 43793;70958 43890;70800 43883 1;70650 43883;70575 43860;70433 43838 1;70298 43830;70268 43980;70238 44100 1;70178 44303;70020 44363;69825 44408 1;69653 44453;69548 44475;69435 44603 1;69180 44888;69420 44498;69458 44865;69765 45240;70260 45585 32;70823 45930;73358 41760 18;69233 40185 1;69360 39540;69548 39053;69758 38250;69225 38925 1;69495 38993;69750 39060;70110 39165 1;70253 39218;70403 39120;70433 38970 1;70477 38738;70515 38625;70538 38385;69233 38228;69233 38933;69225 38925 18;69210 45143 1;69285 45188;69367 45240;69458 45293;69413 45075 1;69443 44933;69413 44850;69367 44707 1;69323 44588;69270 44468;69210 44348;69218 45143;69210 45143 18;69240 37388 1;69360 37402;69473 37418;69637 37425 1;69803 37448;70065 37402;70012 37245 1;69938 37050;69855 36960;69758 36773 1;69698 36683;69683 36630;69645 36525 1;69600 36443;69668 36360;69758 36315 1;69878 36263;69938 36225;70073 36173 1;70170 36143;70193 36045;70185 35933 1;70163 35723;70140 35610;70140 35393 1;70133 35295;70088 35213;69990 35190 1;69765 35160;69668 35085;69450 35040 1;69345 35025;69255 34898;69330 34823 1;69398 34755;69398 34680;69495 34650 1;69518 34643;69480 34613;69473 34582 1;69413 34433;69405 34343;69360 34178 1;69345 34148;69360 34110;69330 34088;69240 34058;69240 37395;69240 37388 18;69248 34050;69330 34088 33;69428 34058;69488 34035;69600 33998 1;69690 33975;69750 34005;69848 34035 1;69990 34095;70073 34178;70110 34328 1;70117 34380;70117 34425;70110 34463 33;70102 34537;70065 34605;69998 34635 1;69795 34733;69660 34665;69495 34650 33;69398 34680;69398 34755;69330 34823 1;69255 34898;69345 35025;69450 35040 1;69668 35085;69765 35160;69990 35190 1;70088 35213;70133 35295;70140 35393 1;70140 35610;70163 35723;70185 35933 1;70193 36045;70170 36143;70073 36173 1;69938 36225;69878 36263;69758 36315 1;69668 36360;69600 36443;69645 36525 1;69683 36630;69698 36683;69758 36773 1;69818 36900;69878 36983;69930 37080;72540 56887 1;72855 56985;73020 56820;73050 56558 1;73050 56363;72953 56048;72637 55950 33;72330 55860;72083 55613;72053 56295 1;72045 56820;71985 56768;72540 56887 18;72833 60473 1;72473 60255;72008 60090;72143 59693 1;72300 59205;72308 58935;72293 58418 1;72270 57758;72255 57375;72233 56730;73980 59153 1;73358 58155;73125 57855;72773 56858;72360 55950 1;72360 55373;72338 55080;72360 54495;87585 73350 1;87675 73020;87818 72600;88148 72698 1;88725 72878;89078 72900;89528 73305 1;89850 73605;89940 73890;89948 74325 1;89948 74805;89970 75135;89648 75473 1;89348 75780;88965 75645;88590 75450 1;88065 75188;87923 74865;87563 74400 1;87308 74085;87465 73808;87585 73350 18;87262 33998;87330 34043 33;87390 34050;87443 34043;87473 33990;87255 33998;87262 33998 18;98565 54585 1;98880 54608;99008 54690;99233 54623 1;99360 54585;99413 54548;99540 54480 1;99600 54450;99608 54420;99615 54345 1;99630 53978;99660 53933;99667 53558 1;99667 53498;99667 53415;99608 53415 1;99315 53415;99128 53393;98895 53385 1;98813 53873;98738 54105;98565 54585 18;70523 46298 1;69863 46035;69795 45443;69210 45082;96839 27067;Forest map sample123255 78068;100740 78000;86288 77955;86602 76852;88110 77108 32;89977 76500 32;90030 73163 32;88913 72428 32;87518 72195 32;89100 68573 32;90375 66968 32;92318 65775 32;97658 64043 32;98828 66338 32;99015 70133 32;99420 72615 32;99830 75218;100312 75150;100140 74078 32;101100 72630 32;101790 72075 32;107190 71760 32;108248 67448 32;108922 64867 32;106598 63195 32;107655 61920 32;111960 62662 32;111960 63435 32;112493 63525 32;112815 62798 32;116250 63278 32;116625 63810 32;116685 64575 32;117608 64537 32;118470 64845 32;120735 65085 32;121703 65018 32;121748 65505 32;122558 65415 32;122753 64927 32;124455 64477;124462 64477;124440 73020;124433 75435;124111 77128;124110 77273 32;123810 77820 32;123255 78068 18;121553 59528;121439 58455;116653 56713;117190 57143;76454 69284 1;76718 68677;76558 67267;77219 67267 1;77998 67267;78614 67769;79287 68161 1;79838 68483;80015 68692;79983 69329 1;79944 70111;79815 70424;79400 71088 1;79109 71553;78866 71605;78394 71326 1;77756 70949;77405 70721;76734 70407 1;76325 70215;76274 69698;76454 69284 18;77063 67349 1;76453 67626;75900 67627;75582 68217 1;75244 68844;74745 69296;75021 69953 1;75367 70774;75898 71195;76756 71433 1;77650 71681;78202 71510;79130 71510;77063 67349 18;82742 72759 1;82742 73189;83015 74001;83319 73697 1;83634 73382;83828 73182;83969 72759 1;84262 71880;83434 70554;84205 70040 1;84646 69746;85256 68794;84782 68557 1;84017 68174;83147 68721;82922 69546 1;82591 70758;82742 71502;82742 72759 18;105741 43279;105210 46148 32;103665 45893 32;102345 45045 32;97583 44123 32;92226 43370 32;89579 43106;88851 42674 32;88282 41889 32;88302 41376;89016 40811;89808 40565;92475 40692 32;97361 41391 32;97728 41725 32;101055 42329 32;105741 43279 18;115695 62535 32;109928 61552 32;109860 60953 32;109373 60953 32;109320 61425 32;108135 61223;109253 59775;109823 56783 32;111727 56595 32;111330 53880 32;113468 53595 32;115485 48720 32;118740 48135 32;118710 47550 32;121255 47315;121230 46298;124515 46223;124523 46223;124500 53093;123450 52935 32;121650 53093 32;121613 52867 32;121387 52748 32;121364 51785;120337 51300 32;120278 50835 32;119025 50430 32;117915 50453 32;117608 50100 32;116873 50168 32;116925 51180 32;117585 51600 32;118268 51563 32;118598 51802 32;119370 51802 32;119723 51518 32;120908 52148 32;120893 53332 32;119422 53820 32;118193 54563 32;117128 54653 32;117128 55260 32;116828 55545 32;115005 55755 32;115087 56145 32;115433 56115 32;115575 57052 32;114968 58635 32;113145 58860 32;113198 59213 32;114908 59025 32;115087 60465 32;114292 60608 32;114345 61095 32;115110 61005 32;115695 62535 50;69135 68858 1;71648 70628;73065 71580;75713 73440 1;77543 74738;78413 75458;80175 76845 1;80723 77288;81060 77535;81510 77940;73898 39547;73831 57316 32;86485 68962 32;95909 51662 32;107957 61624;66336 59806;194054 71555;2103860 48507;395595 34020;95400 35513;95438 36923 32;95460 37560;96165 39255;95850 39795 32;88463 39450 32;88497 37321 32;88508 36630;88538 35287;88628 34755;88755 33998;95595 34020;95400 35513;95438 36923 32;95460 37560;96165 39255;95850 39795 32;88463 39450;88497 37321 32;88508 36630;88538 35287;88628 34755;88755 33998;95595 34020;95400 35513;95438 36923 32;95460 37560;96165 39255;95850 39795 32;88463 39450 32;88497 37321 32;88508 36630;88538 35287;88628 34755;88755 33998;95595 34020;95400 35513;95438 36923 32;95460 37560;96165 39255;95850 39795 32;88463 39450 32;88497 37321;88508 36630;88538 35287;88628 34755;88755 33998;95595 34020;95400 35513;95438 36923 32;95460 37560;96165 39255;95850 39795 32;88463 39450 32;88497 37321;88508 36630 32;88538 35287;88628 34755;88755 33998;95595 34020;95400 35513;95438 36923 32;95460 37560;96165 39255;95850 39795 32;88463 39450 32;88497 37321;88508 36630;88538 35287;88628 34755;88755 33998;95595 34020;95400 35513;95438 36923 32;95460 37560;96165 39255;95850 39795 32;88463 39450 32;88497 37321;88508 36630 32;88538 35287;88628 34755;88755 33998;95595 34020;95400 35513;95438 36923 32;95460 37560;96165 39255;95850 39795 32;88463 39450 32;88497 37321;88508 36630;88538 35287;88628 34755;88755 33998;95595 34020;95400 35513;95438 36923 32;95460 37560;96165 39255;95850 39795 32;88463 39450 32;88497 37321 32;88508 36630;88538 35287;88628 34755;88755 33998;95595 34020;95400 35513;95438 36923 32;95460 37560;96165 39255;95850 39795 32;88463 39450 32;88497 37321;88508 36630;88538 35287;88628 34755;88755 33998;95595 34020;95400 35513;95438 36923 32;95460 37560;96165 39255;95850 39795 32;88463 39450 32;88497 37321;88508 36630 32;88538 35287;88628 34755;88755 33998;95595 34020;95400 35513;95438 36923 32;95460 37560;96165 39255;95850 39795 32;88463 39450 32;88497 37321 32;88508 36630 32;88538 35287;88628 34755;88755 33998;95595 34020;95400 35513;95438 36923 32;95460 37560;96165 39255;95850 39795 32;88463 39450 32;88497 37321;88508 36630 32;88538 35287;88628 34755;88755 33998;95595 34020;95400 35513;95438 36923 32;95460 37560;96165 39255;95850 39795 32;88463 39450 32;88497 37321;88508 36630;88538 35287;88628 34755;88755 33998;105741 43279;105210 46148 32;103665 45893 32;102345 45045 32;97583 44123 32;92226 43370 32;89579 43106;88851 42674 32;88282 41889 32;88302 41376;89016 40811;89808 40565;92475 40692 32;97361 41391 32;97728 41725 32;101055 42329 32;105741 43279 18;105741 43279;105210 46148 32;103665 45893 32;102345 45045 32;97583 44123 32;92226 43370 32;89579 43106;88851 42674 32;88282 41889;88302 41376;89016 40811;89808 40565;92475 40692 32;97361 41391 32;97728 41725 32;101055 42329 32;105741 43279 18;105741 43279;105210 46148;103665 45893 32;102345 45045 32;97583 44123 32;92226 43370 32;89579 43106;88851 42674 32;88282 41889;88302 41376;89016 40811;89808 40565;92475 40692 32;97361 41391 32;97728 41725 32;101055 42329 32;105741 43279 18;105741 43279;105210 46148 32;103665 45893 32;102345 45045 32;97583 44123 32;92226 43370 32;89579 43106;88851 42674 32;88282 41889;88302 41376;89016 40811;89808 40565;92475 40692 32;97361 41391 32;97728 41725 32;101055 42329 32;105741 43279 18;105741 43279;105210 46148 32;103665 45893 32;102345 45045 32;97583 44123 32;92226 43370 32;89579 43106;88851 42674 32;88282 41889;88302 41376;89016 40811;89808 40565;92475 40692 32;97361 41391 32;97728 41725 32;101055 42329;105741 43279 18;105741 43279;105210 46148 32;103665 45893 32;102345 45045 32;97583 44123 32;92226 43370 32;89579 43106;88851 42674 32;88282 41889;88302 41376;89016 40811;89808 40565;92475 40692 32;97361 41391 32;97728 41725 32;101055 42329 32;105741 43279 18;105741 43279;105210 46148 32;103665 45893 32;102345 45045 32;97583 44123 32;92226 43370 32;89579 43106;88851 42674 32;88282 41889;88302 41376;89016 40811;89808 40565;92475 40692 32;97361 41391 32;97728 41725 32;101055 42329;105741 43279 18;105741 43279;105210 46148 32;103665 45893 32;102345 45045 32;97583 44123 32;92226 43370 32;89579 43106;88851 42674 32;88282 41889;88302 41376;89016 40811;89808 40565;92475 40692 32;97361 41391 32;97728 41725 32;101055 42329 32;105741 43279 18;105741 43279;105210 46148 32;103665 45893 32;102345 45045 32;97583 44123 32;92226 43370 32;89579 43106;88851 42674 32;88282 41889;88302 41376;89016 40811;89808 40565;92475 40692 32;97361 41391 32;97728 41725;101055 42329 32;105741 43279 18;105741 43279;105210 46148 32;103665 45893 32;102345 45045 32;97583 44123 32;92226 43370 32;89579 43106;88851 42674 32;88282 41889;88302 41376;89016 40811;89808 40565;92475 40692 32;97361 41391;97728 41725;101055 42329 32;105741 43279 18;105741 43279;105210 46148 32;103665 45893 32;102345 45045;97583 44123 32;92226 43370 32;89579 43106;88851 42674 32;88282 41889;88302 41376;89016 40811;89808 40565;92475 40692 32;97361 41391;97728 41725;101055 42329 32;105741 43279 18;119220 43928;115898 44108 32;112658 44033 32;109500 43140 32;109493 41123 32;109485 39743 32;109485 38348 32;110948 38340 32;114120 38318 32;114450 40470 32;115852 41730 32;115852 42428 32;116325 42428 32;116325 41738 32;118500 40335 32;118605 37103 32;122085 38655 32;124553 37553;119220 43928;115898 44108 32;112658 44033 32;109500 43140 32;109493 41123 32;109485 39743 32;109485 38348 32;110948 38340 32;114120 38318 32;114450 40470 32;115852 41730 32;115852 42428 32;116325 42428;116325 41738 32;118500 40335 32;118605 37103 32;122085 38655 32;124553 37553;119220 43928;115898 44108 32;112658 44033 32;109500 43140 32;109493 41123 32;109485 39743 32;109485 38348 32;110948 38340 32;114120 38318 32;114450 40470 32;115852 41730 32;115852 42428 32;116325 42428 32;116325 41738 32;118500 40335 32;118605 37103 32;122085 38655 32;124553 37553;119220 43928;115898 44108 32;112658 44033 32;109500 43140 32;109493 41123 32;109485 39743 32;109485 38348 32;110948 38340 32;114120 38318 32;114450 40470 32;115852 41730 32;115852 42428 32;116325 42428 32;116325 41738;118500 40335 32;118605 37103 32;122085 38655 32;124553 37553;119220 43928;115898 44108 32;112658 44033 32;109500 43140 32;109493 41123 32;109485 39743 32;109485 38348 32;110948 38340 32;114120 38318 32;114450 40470 32;115852 41730 32;115852 42428 32;116325 42428;116325 41738;118500 40335 32;118605 37103 32;122085 38655 32;124553 37553;119220 43928;115898 44108 32;112658 44033 32;109500 43140 32;109493 41123 32;109485 39743 32;109485 38348 32;110948 38340 32;114120 38318 32;114450 40470 32;115852 41730 32;115852 42428;116325 42428;116325 41738;118500 40335 32;118605 37103 32;122085 38655 32;124553 37553;119220 43928;115898 44108 32;112658 44033 32;109500 43140 32;109493 41123 32;109485 39743 32;109485 38348 32;110948 38340 32;114120 38318 32;114450 40470 32;115852 41730;115852 42428;116325 42428;116325 41738;118500 40335 32;118605 37103 32;122085 38655 32;124553 37553;119220 43928;115898 44108 32;112658 44033 32;109500 43140 32;109493 41123 32;109485 39743 32;109485 38348 32;110948 38340 32;114120 38318 32;114450 40470;115852 41730;115852 42428;116325 42428;116325 41738;118500 40335 32;118605 37103 32;122085 38655 32;124553 37553;119220 43928;115898 44108 32;112658 44033 32;109500 43140 32;109493 41123 32;109485 39743 32;109485 38348 32;110948 38340 32;114120 38318 32;114450 40470 32;115852 41730;115852 42428;116325 42428;116325 41738;118500 40335 32;118605 37103 32;122085 38655 32;124553 37553;119220 43928;115898 44108 32;112658 44033 32;109500 43140 32;109493 41123 32;109485 39743 32;109485 38348 32;110948 38340 32;114120 38318 32;114450 40470 32;115852 41730;115852 42428;116325 42428 32;116325 41738;118500 40335 32;118605 37103 32;122085 38655 32;124553 37553;119220 43928;115898 44108 32;112658 44033 32;109500 43140 32;109493 41123 32;109485 39743 32;109485 38348 32;110948 38340 32;114120 38318 32;114450 40470 32;115852 41730;115852 42428 32;116325 42428 32;116325 41738;118500 40335 32;118605 37103 32;122085 38655 32;124553 37553;119220 43928;115898 44108 32;112658 44033 32;109500 43140 32;109493 41123 32;109485 39743 32;109485 38348 32;110948 38340 32;114120 38318 32;114450 40470 32;115852 41730;115852 42428;116325 42428 32;116325 41738;118500 40335 32;118605 37103 32;122085 38655 32;124553 37553;119220 43928;115898 44108 32;112658 44033 32;109500 43140 32;109493 41123 32;109485 39743 32;109485 38348 32;110948 38340 32;114120 38318 32;114450 40470 32;115852 41730 32;115852 42428;116325 42428 32;116325 41738;118500 40335 32;118605 37103 32;122085 38655 32;124553 37553;119220 43928;115898 44108 32;112658 44033 32;109500 43140 32;109493 41123 32;109485 39743 32;109485 38348 32;110948 38340 32;114120 38318 32;114450 40470 32;115852 41730 32;115852 42428 32;116325 42428 32;116325 41738;118500 40335 32;118605 37103 32;122085 38655 32;124553 37553;119220 43928;115898 44108 32;112658 44033 32;109500 43140 32;109493 41123 32;109485 39743 32;109485 38348 32;110948 38340 32;114120 38318 32;114450 40470 32;115852 41730 32;115852 42428;116325 42428 32;116325 41738;118500 40335 32;118605 37103 32;122085 38655 32;124553 37553;124545 37508;122010 38648 32;118598 37140 32;118508 40358 32;116333 41738;116265 42375;115868 42353 32;115837 41738 32;114420 40470 32;114075 38340 32;109523 38348 32;109448 43155 32;112613 44033 32;119220 43943 32;124530 43695;124553 37508;124545 37508 18;124545 37508;122010 38648 32;118598 37140 32;118508 40358 32;116333 41738;116265 42375;115868 42353 32;115837 41738;114420 40470 32;114075 38340 32;109523 38348 32;109448 43155 32;112613 44033 32;119220 43943 32;124530 43695;124553 37508;124545 37508 18;124545 37508;122010 38648 32;118598 37140 32;118508 40358 32;116333 41738;116265 42375;115868 42353 32;115837 41738 32;114420 40470 32;114075 38340 32;109523 38348 32;109448 43155 32;112613 44033 32;119220 43943 32;124530 43695;124553 37508;124545 37508 18;124545 37508;122010 38648 32;118598 37140 32;118508 40358 32;116333 41738;116265 42375;115868 42353 32;115837 41738 32;114420 40470;114075 38340 32;109523 38348 32;109448 43155 32;112613 44033 32;119220 43943 32;124530 43695;124553 37508;124545 37508 18;107977 61328;109290 59745 32;109778 56753 32;111743 56580 32;111345 53918 32;113438 53565 32;115530 48675 32;117855 48293 32;118710 48150 32;118643 47520 32;119880 47445 32;121268 47355 32;107977 61328;109290 59745 32;109778 56753 32;111743 56580 32;111345 53918 32;113438 53565 32;115530 48675 32;117855 48293 32;118710 48150;118643 47520 32;119880 47445 32;121268 47355 32;107977 61328;109290 59745 32;109778 56753 32;111743 56580 32;111345 53918 32;113438 53565 32;115530 48675 32;117855 48293;118710 48150;118643 47520 32;119880 47445 32;121268 47355 32;107977 61328;109290 59745 32;109778 56753 32;111743 56580 32;111345 53918 32;113438 53565 32;115530 48675 32;118710 48150;118643 47520 32;119880 47445 32;121268 47355 32;86280 77955;86595 76823 32;88125 77093 32;89985 76545 32;90015 73095 32;88875 72420 32;87465 72203 32;89168 68550;90420 66930 32;92348 65805 32;97688 64012 32;98828 66390;98977 70193 32;99893 75285;86280 77955;86595 76823 32;88125 77093 32;89985 76545 32;90015 73095 32;88875 72420;87465 72203 32;89168 68550;90420 66930 32;92348 65805 32;97688 64012 32;98828 66390;98977 70193 32;99893 75285;86280 77955;86595 76823 32;88125 77093;89985 76545 32;90015 73095 32;88875 72420;87465 72203 32;89168 68550;90420 66930 32;92348 65805 32;97688 64012 32;98828 66390;98977 70193 32;99893 75285; +The purple line will extend a bit into the finish symbol. This is a shortcoming of this simple approach.3041 0;3541 0;-3021 3500;3041 0;-3021 -3500;-3021 3500 18;-600 0;600 0;0 0;The OpenOrienteering Logo.-12797 -557 1;-12755 -447;-12770 -420;-12873 -420 1;-12953 -420;-12973 -440;-12973 -520 1;-12973 -635;-12838 -663;-12797 -557 18;-933 2063 1;-933 1925;-920 1900;-851 1900 1;-780 1900;-770 1921;-781 2050 1;-789 2154;-814 2203;-863 2213 1;-920 2224;-933 2197;-933 2063;-933 2063 18;-8875 -3860 1;-8922 -3920;-8984 -3968;-9061 -4006 1;-9134 -4045;-9225 -4065;-9337 -4065 1;-9444 -4065;-9535 -4045;-9612 -4006 1;-9688 -3974;-9752 -3927;-9803 -3867 1;-9855 -3807;-9895 -3737;-9925 -3655 1;-9950 -3578;-9970 -3500;-9982 -3418;-8723 -3418 1;-8725 -3500;-8740 -3578;-8768 -3655 1;-8789 -3732;-8824 -3800;-8875 -3860 18;-4230 -3923 1;-4183 -3737;-4160 -3527;-4160 -3296;-4160 -1395;-5113 -1395;-5113 -3182 1;-5113 -3488;-5155 -3707;-5235 -3833 1;-5317 -3961;-5468 -4027;-5690 -4027 1;-5759 -4027;-5830 -4021;-5907 -4013 1;-5983 -4008;-6052 -4004;-6112 -3993;-6112 -1395;-7064 -1395;-7064 -4646 1;-6903 -4693;-6694 -4736;-6438 -4774 1;-6181 -4818;-5913 -4838;-5631 -4838 1;-5347 -4838;-5110 -4800;-4921 -4723 1;-4730 -4652;-4579 -4547;-4467 -4410 1;-4357 -4273;-4277 -4111;-4230 -3923 18;-13524 1118 1;-13605 1126;-13667 1137;-13708 1150;-13708 3722;-14662 3722;-14662 536 1;-14492 476;-14292 420;-14060 369 1;-13827 314;-13565 286;-13280 286 1;-13229 286;-13167 290;-13096 299 1;-13022 303;-12951 312;-12878 325 1;-12806 333;-12733 345;-12660 363 1;-12587 375;-12526 392;-12474 414;-12634 1201 1;-12719 1180;-12819 1158;-12936 1137 1;-13051 1112;-13174 1098;-13306 1098 1;-13366 1098;-13439 1105;-13524 1118 18;-11093 -200 1;-11204 -101;-11336 -52;-11490 -52 1;-11642 -52;-11777 -101;-11893 -200 1;-12004 -303;-12059 -441;-12059 -616 1;-12059 -791;-12004 -927;-11893 -1026 1;-11777 -1128;-11642 -1179;-11490 -1179 1;-11336 -1179;-11204 -1128;-11093 -1026 1;-10978 -927;-10920 -791;-10920 -616 1;-10920 -441;-10978 -303;-11093 -200 18;-11009 3722;-11963 3722;-11963 357;-11009 357;-11009 3722 18;-8649 1053 1;-8755 1053;-8847 1073;-8924 1112 1;-9001 1145;-9065 1192;-9115 1252 1;-9167 1312;-9207 1381;-9237 1464 1;-9264 1539;-9282 1618;-9296 1700;-8034 1700 1;-8039 1618;-8054 1539;-8079 1464 1;-8101 1387;-8137 1318;-8189 1259 1;-8236 1199;-8297 1150;-8374 1112 1;-8445 1073;-8537 1053;-8649 1053 18;-5220 1105 1;-5297 1110;-5365 1115;-5425 1125;-5425 3722;-6378 3722;-6378 472 1;-6217 425;-6007 382;-5751 344 1;-5495 301;-5227 280;-4945 280 1;-4658 280;-4422 318;-4235 395 1;-4042 467;-3890 572;-3781 709 1;-3669 845;-3591 1007;-3544 1195 1;-3497 1381;-3474 1592;-3474 1821;-3474 3722;-4427 3722;-4427 1937 1;-4427 1630;-4467 1411;-4549 1285 1;-4628 1156;-4780 1092;-5002 1092 1;-5070 1092;-5143 1097;-5220 1105 18;-2636 2346;-2636 -481;-1683 -634;-1683 357;-539 357;-539 1150;-1683 1150;-1683 2333 1;-1683 2535;-1648 2694;-1581 2813 1;-1508 2933;-1365 2993;-1151 2993 1;-1050 2993;-945 2984;-838 2966 1;-728 2946;-627 2918;-539 2884;-404 3626 1;-518 3673;-646 3712;-787 3748 1;-928 3780;-1102 3799;-1305 3799 1;-1566 3799;-1781 3764;-1951 3696 1;-2123 3624;-2259 3526;-2361 3402 1;-2463 3274;-2536 3121;-2579 2941 1;-2618 2763;-2636 2565;-2636 2346 18;2142 1464 1;2121 1387;2084 1318;2032 1259 1;1986 1199;1924 1150;1847 1112 1;1776 1073;1685 1053;1572 1053 1;1466 1053;1375 1073;1298 1112 1;1221 1145;1156 1192;1106 1252 1;1054 1312;1014 1381;984 1464 1;958 1539;939 1618;926 1700;2187 1700 1;2183 1618;2168 1539;2142 1464 18;5923 1700 1;5919 1618;5904 1539;5878 1464 1;5856 1387;5821 1318;5769 1259 1;5723 1199;5661 1150;5585 1112 1;5511 1073;5419 1053;5308 1053 1;5201 1053;5110 1073;5033 1112 1;4957 1145;4893 1192;4841 1252 1;4790 1312;4750 1381;4720 1464 1;4695 1539;4675 1618;4663 1700;5923 1700 18;8718 1118 1;8637 1126;8575 1137;8534 1150;8534 3722;7581 3722;7581 536 1;7750 476;7950 420;8182 369 1;8415 314;8677 286;8962 286 1;9013 286;9075 290;9146 299 1;9220 303;9292 312;9365 325 1;9437 333;9510 345;9583 363 1;9655 375;9717 392;9768 414;9608 1201 1;9523 1180;9424 1158;9306 1137 1;9191 1112;9069 1098;8937 1098 1;8877 1098;8804 1105;8718 1118 18;10350 -200 1;10238 -303;10183 -441;10183 -616 1;10183 -791;10238 -927;10350 -1026 1;10465 -1128;10600 -1179;10752 -1179 1;10906 -1179;11038 -1128;11149 -1026 1;11264 -927;11323 -791;11323 -616 1;11323 -441;11264 -303;11149 -200 1;11038 -101;10906 -52;10752 -52 1;10600 -52;10465 -101;10350 -200 18;11233 3722;10279 3722;10279 357;11233 357;11233 3722 18;14726 709 1;14836 845;14916 1007;14963 1195 1;15010 1381;15033 1592;15033 1821;15033 3722;14080 3722;14080 1937 1;14080 1630;14039 1411;13958 1285 1;13876 1156;13725 1092;13504 1092 1;13435 1092;13363 1097;13287 1105 1;13210 1110;13142 1115;13082 1125;13082 3722;12129 3722;12129 472 1;12290 425;12499 382;12756 344 1;13012 301;13280 280;13562 280 1;13847 280;14083 318;14272 395 1;14463 467;14614 572;14726 709 18;-17051 -1307 1;-17299 -1307;-17525 -1349;-17729 -1434 1;-17931 -1521;-18102 -1639;-18247 -1794 1;-18392 -1951;-18505 -2139;-18587 -2355 1;-18669 -2579;-18708 -2820;-18708 -3085 1;-18708 -3350;-18669 -3591;-18587 -3808 1;-18502 -4027;-18387 -4211;-18242 -4365 1;-18092 -4518;-17917 -4638;-17717 -4723 1;-17512 -4808;-17291 -4851;-17051 -4851 1;-16808 -4851;-16586 -4808;-16386 -4723 1;-16182 -4638;-16006 -4518;-15861 -4365 1;-15716 -4211;-15603 -4027;-15523 -3808 1;-15442 -3591;-15401 -3350;-15401 -3085 1;-15401 -2820;-15440 -2579;-15517 -2355 1;-15593 -2139;-15703 -1951;-15848 -1794 1;-15993 -1639;-16168 -1521;-16373 -1434 1;-16574 -1349;-16800 -1307;-17051 -1307 18;-17051 -2126 1;-16834 -2126;-16668 -2210;-16552 -2383 1;-16433 -2557;-16373 -2792;-16373 -3085 1;-16373 -3380;-16433 -3610;-16552 -3777 1;-16668 -3946;-16834 -4034;-17051 -4034 1;-17269 -4034;-17437 -3946;-17557 -3777 1;-17675 -3610;-17736 -3380;-17736 -3085 1;-17736 -2792;-17675 -2557;-17557 -2383 1;-17437 -2210;-17269 -2126;-17051 -2126 18;-14662 -213;-14662 -4646 1;-14576 -4673;-14478 -4697;-14369 -4716 1;-14257 -4743;-14142 -4765;-14022 -4781 1;-13898 -4798;-13776 -4811;-13652 -4819 1;-13524 -4833;-13402 -4838;-13287 -4838 1;-13009 -4838;-12763 -4796;-12544 -4711 1;-12328 -4630;-12144 -4513;-11995 -4358 1;-11846 -4210;-11732 -4027;-11657 -3808 1;-11574 -3591;-11535 -3348;-11535 -3078 1;-11535 -2819;-11566 -2582;-11629 -2368 1;-11694 -2156;-11788 -1972;-11911 -1819 1;-12034 -1666;-12189 -1546;-12373 -1461 1;-12556 -1376;-12765 -1333;-13006 -1333 1;-13137 -1333;-13261 -1346;-13377 -1371 1;-13492 -1395;-13602 -1432;-13708 -1479;-13708 -213;-14662 -213 18;-13184 -2139 1;-12733 -2139;-12506 -2443;-12506 -3054 1;-12506 -3348;-12572 -3582;-12704 -3756 1;-12837 -3936;-13032 -4027;-13293 -4027 1;-13379 -4027;-13457 -4021;-13530 -4013 1;-13602 -4008;-13662 -4004;-13708 -3993;-13708 -2274 1;-13648 -2234;-13572 -2202;-13479 -2177 1;-13381 -2152;-13282 -2139;-13184 -2139 18;-9182 -1307 1;-9485 -1307;-9750 -1352;-9976 -1440 1;-10198 -1530;-10383 -1652;-10533 -1806 1;-10678 -1964;-10787 -2149;-10858 -2362 1;-10926 -2575;-10962 -2807;-10962 -3054 1;-10962 -3352;-10917 -3612;-10827 -3833 1;-10733 -4060;-10611 -4248;-10462 -4396 1;-10314 -4547;-10141 -4660;-9950 -4736 1;-9754 -4813;-9553 -4851;-9349 -4851 1;-8872 -4851;-8494 -4705;-8217 -4410 1;-7939 -4120;-7801 -3692;-7801 -3123 1;-7801 -3069;-7803 -3007;-7808 -2939 1;-7810 -2873;-7816 -2817;-7819 -2766;-9982 -2766 1;-9961 -2569;-9870 -2413;-9707 -2299 1;-9545 -2184;-9327 -2126;-9055 -2126 1;-8881 -2126;-8708 -2141;-8542 -2171 1;-8372 -2205;-8234 -2246;-8127 -2292;-7999 -1517 1;-8051 -1493;-8119 -1468;-8204 -1440 1;-8289 -1416;-8385 -1395;-8492 -1378 1;-8594 -1356;-8706 -1339;-8824 -1326 1;-8944 -1314;-9063 -1307;-9182 -1307 18;-9982 -3418;-8723 -3418 1;-8725 -3500;-8740 -3578;-8768 -3655 1;-8789 -3732;-8824 -3800;-8875 -3860 1;-8922 -3920;-8984 -3968;-9061 -4006 1;-9134 -4045;-9225 -4065;-9337 -4065 1;-9444 -4065;-9535 -4045;-9612 -4006 1;-9688 -3974;-9752 -3927;-9803 -3867 1;-9855 -3807;-9895 -3737;-9925 -3655 1;-9950 -3578;-9970 -3500;-9982 -3418 18;-17051 -2126 1;-17269 -2126;-17437 -2210;-17557 -2383 1;-17675 -2557;-17736 -2792;-17736 -3085 1;-17736 -3380;-17675 -3610;-17557 -3777 1;-17437 -3946;-17269 -4034;-17051 -4034 1;-16834 -4034;-16668 -3946;-16552 -3777 1;-16433 -3610;-16373 -3380;-16373 -3085 1;-16373 -2792;-16433 -2557;-16552 -2383 1;-16668 -2210;-16834 -2126;-17051 -2126 18;-17064 -2593 1;-16944 -2591;-16842 -2808;-16838 -3077 1;-16834 -3347;-16928 -3567;-17049 -3569 1;-17170 -3571;-17271 -3354;-17275 -3084 1;-17280 -2815;-17185 -2595;-17064 -2593 18;-8496 3810 1;-8798 3810;-9062 3765;-9288 3677 1;-9510 3588;-9696 3466;-9845 3312 1;-9990 3154;-10098 2969;-10171 2756 1;-10240 2542;-10273 2311;-10273 2065 1;-10273 1766;-10230 1507;-10140 1285 1;-10045 1058;-9923 870;-9775 722 1;-9625 572;-9455 459;-9264 382 1;-9067 305;-8867 267;-8662 267 1;-8184 267;-7806 414;-7529 709 1;-7252 998;-7113 1426;-7113 1995 1;-7113 2050;-7116 2112;-7119 2180 1;-7124 2245;-7128 2301;-7132 2353;-9296 2353 1;-9273 2550;-9182 2704;-9020 2820 1;-8857 2934;-8640 2993;-8368 2993 1;-8193 2993;-8022 2978;-7855 2948 1;-7684 2912;-7546 2873;-7440 2826;-7311 3601 1;-7363 3626;-7431 3651;-7516 3677 1;-7603 3703;-7697 3724;-7804 3741 1;-7908 3763;-8017 3779;-8137 3793 1;-8257 3804;-8376 3810;-8496 3810 18;-9296 1700;-8034 1700 1;-8039 1618;-8054 1539;-8079 1464 1;-8101 1387;-8137 1318;-8189 1259 1;-8236 1199;-8297 1150;-8374 1112 1;-8445 1073;-8537 1053;-8649 1053 1;-8755 1053;-8847 1073;-8924 1112 1;-9001 1145;-9065 1192;-9115 1252 1;-9167 1312;-9207 1381;-9237 1464 1;-9264 1539;-9282 1618;-9296 1700 18;1726 3810 1;1422 3810;1159 3765;933 3677 1;712 3588;524 3466;376 3312 1;231 3154;123 2969;49 2756 1;-19 2542;-52 2311;-52 2065 1;-52 1766;-9 1507;81 1285 1;177 1058;298 870;446 722 1;596 572;766 459;958 382 1;1154 305;1354 267;1559 267 1;2038 267;2416 414;2692 709 1;2968 998;3109 1426;3109 1995 1;3109 2050;3105 2112;3102 2180 1;3097 2245;3094 2301;3088 2353;926 2353 1;947 2550;1039 2704;1201 2820 1;1364 2934;1581 2993;1854 2993 1;2029 2993;2199 2978;2365 2948 1;2538 2912;2675 2873;2782 2826;2910 3601 1;2859 3626;2790 3651;2705 3677 1;2619 3703;2524 3724;2417 3741 1;2314 3763;2204 3779;2084 3793 1;1965 3804;1846 3810;1726 3810 18;926 1700;2187 1700 1;2183 1618;2168 1539;2142 1464 1;2121 1387;2084 1318;2032 1259 1;1986 1199;1924 1150;1847 1112 1;1776 1073;1685 1053;1572 1053 1;1466 1053;1375 1073;1298 1112 1;1221 1145;1156 1192;1106 1252 1;1054 1312;1014 1381;984 1464 1;958 1539;939 1618;926 1700 18;5463 3810 1;5160 3810;4895 3765;4668 3677 1;4446 3588;4262 3466;4112 3312 1;3967 3154;3858 2969;3787 2756 1;3719 2542;3684 2311;3684 2065 1;3684 1766;3729 1507;3819 1285 1;3911 1058;4033 870;4183 722 1;4332 572;4503 459;4695 382 1;4891 305;5091 267;5297 267 1;5773 267;6151 414;6428 709 1;6706 998;6844 1426;6844 1995 1;6844 2050;6843 2112;6837 2180 1;6834 2245;6829 2301;6826 2353;4663 2353 1;4683 2550;4775 2704;4938 2820 1;5100 2934;5318 2993;5590 2993 1;5765 2993;5936 2978;6103 2948 1;6272 2912;6411 2873;6518 2826;6646 3601 1;6594 3626;6526 3651;6441 3677 1;6356 3703;6259 3724;6152 3741 1;6051 3763;5939 3779;5821 3793 1;5701 3804;5581 3810;5463 3810 18;4663 1700;5923 1700 1;5919 1618;5904 1539;5878 1464 1;5856 1387;5821 1318;5769 1259 1;5723 1199;5661 1150;5585 1112 1;5511 1073;5419 1053;5308 1053 1;5201 1053;5110 1073;5033 1112 1;4957 1145;4893 1192;4841 1252 1;4790 1312;4750 1381;4720 1464 1;4695 1539;4675 1618;4663 1700 18;17092 4924 1;16887 4924;16682 4905;16477 4867 1;16272 4832;16083 4785;15908 4725;16074 3926 1;16224 3986;16379 4032;16543 4067 1;16707 4101;16896 4119;17105 4119 1;17377 4119;17570 4059;17680 3939 1;17796 3819;17854 3666;17854 3479;17854 3357 1;17750 3404;17644 3441;17533 3466 1;17427 3487;17309 3498;17182 3498 1;16717 3498;16361 3361;16113 3087 1;15866 2811;15743 2424;15743 1930 1;15743 1683;15781 1458;15857 1259 1;15934 1053;16044 878;16189 733 1;16339 589;16521 478;16734 402 1;16947 320;17187 280;17457 280 1;17572 280;17689 286;17809 299 1;17931 307;18053 320;18173 337 1;18292 354;18405 375;18512 402 1;18624 422;18722 446;18806 472;18806 3299 1;18806 3849;18665 4257;18385 4522 1;18107 4790;17677 4924;17092 4924 18;17360 2730 1;17459 2730;17550 2718;17636 2691 1;17720 2666;17794 2636;17854 2603;17854 1080 1;17807 1072;17750 1065;17687 1060 1;17623 1052;17548 1047;17464 1047 1;17212 1047;17024 1130;16900 1297 1;16776 1464;16714 1675;16714 1930 1;16714 2463;16930 2730;17360 2730 18;-17051 2993 1;-17269 2993;-17437 2908;-17557 2736 1;-17675 2561;-17736 2326;-17736 2033 1;-17736 1738;-17675 1509;-17557 1342 1;-17437 1171;-17269 1085;-17051 1085 1;-16834 1085;-16668 1171;-16552 1342 1;-16433 1509;-16373 1738;-16373 2033 1;-16373 2326;-16433 2561;-16552 2736 1;-16668 2908;-16834 2993;-17051 2993 18;-17064 2526 1;-16944 2528;-16842 2311;-16838 2042 1;-16834 1772;-16928 1552;-17049 1550 1;-17170 1548;-17271 1765;-17275 2035 1;-17280 2304;-17185 2524;-17064 2526 18;-17051 3810 1;-17299 3810;-17525 3769;-17729 3684 1;-17931 3598;-18102 3479;-18247 3324 1;-18392 3168;-18505 2980;-18587 2763 1;-18669 2540;-18708 2298;-18708 2033 1;-18708 1768;-18669 1526;-18587 1310 1;-18502 1092;-18387 906;-18242 754 1;-18092 600;-17917 480;-17717 395 1;-17512 310;-17291 267;-17051 267 1;-16808 267;-16586 310;-16386 395 1;-16182 480;-16006 600;-15861 754 1;-15716 906;-15603 1092;-15523 1310 1;-15442 1526;-15401 1768;-15401 2033 1;-15401 2298;-15440 2540;-15517 2763 1;-15593 2980;-15703 3168;-15848 3324 1;-15993 3479;-16168 3598;-16373 3684 1;-16574 3769;-16800 3810;-17051 3810 18;-17051 2993 1;-16834 2993;-16668 2908;-16552 2736 1;-16433 2561;-16373 2326;-16373 2033 1;-16373 1738;-16433 1509;-16552 1342 1;-16668 1171;-16834 1085;-17051 1085 1;-17269 1085;-17437 1171;-17557 1342 1;-17675 1509;-17736 1738;-17736 2033 1;-17736 2326;-17675 2561;-17557 2736 1;-17437 2908;-17269 2993;-17051 2993 18;17090 5390 1;16864 5390;16623 5362;16391 5321 1;16389 5320;16389 5320;16387 5320 1;16169 5284;15963 5240;15758 5170 1;15555 5102;15409 4847;15450 4637 1;15450 4635;15450 4634;15450 4632;15538 4221 1;15549 4165;15526 4109;15478 4079 1;15431 4049;15369 4052;15324 4088 1;15245 4152;15138 4191;15033 4191;14080 4191 1;13930 4193;13775 4107;13692 3983 1;13669 3944;13625 3921;13580 3921 1;13534 3921;13492 3944;13466 3983 1;13385 4107;13233 4191;13083 4191;12131 4191 1;12001 4191;11866 4131;11781 4032 1;11755 4004;11719 3987;11680 3987 1;11642 3987;11606 4004;11581 4032 1;11496 4131;11364 4191;11234 4191;10281 4191 1;10048 4193;9815 3957;9815 3724;9815 1796 1;9815 1758;9798 1721;9770 1697 1;9741 1670;9703 1658;9665 1663 1;9608 1670;9553 1668;9498 1655 1;9433 1638;9341 1618;9227 1597 1;9221 1595;9217 1593;9210 1592 1;9161 1582;9142 1582;9157 1584 1;9118 1578;9078 1590;9048 1615 1;9018 1640;9001 1678;9001 1716 1;9001 1716;9001 3724;9001 3724 1;9001 3957;8768 4193;8535 4191;7582 4191 1;7424 4191;7262 4099;7183 3962 1;7162 3926;7125 3900;7082 3894 1;7040 3889;6999 3902;6969 3932 1;6935 3966;6899 3996;6855 4016 1;6768 4059;6679 4092;6574 4124 1;6467 4157;6364 4178;6253 4195 1;6244 4197;6236 4199;6226 4202 1;6107 4227;5991 4240;5870 4254 1;5738 4267;5601 4279;5461 4279 1;5121 4279;4808 4231;4520 4120 1;4514 4118;4506 4114;4498 4110 1;4220 3998;3977 3840;3778 3636 1;3717 3566;3663 3494;3609 3412 1;3571 3361;3503 3344;3445 3371 1;3389 3396;3357 3459;3370 3521 1;3404 3711;3293 3930;3120 4016 1;3034 4060;2945 4092;2837 4124 1;2732 4157;2628 4178;2517 4195 1;2508 4197;2499 4199;2490 4202 1;2372 4227;2256 4240;2134 4254 1;2001 4267;1866 4279;1726 4279 1;1386 4279;1071 4231;785 4120 1;778 4118;771 4114;761 4110 1;562 4029;383 3917;218 3782 1;186 3757;145 3748;105 3757 1;64 3765;32 3793;13 3829 1;-35 3929;-124 4013;-229 4054 1;-362 4109;-512 4164;-678 4204 1;-871 4251;-1073 4266;-1303 4266 1;-1606 4266;-1876 4227;-2127 4126 1;-2355 4031;-2561 3892;-2717 3706 1;-2719 3701;-2721 3699;-2719 3702 1;-2716 3707;-2718 3706;-2721 3700 1;-2724 3694;-2734 3667;-2764 3624 1;-2799 3577;-2859 3558;-2915 3576 1;-2969 3594;-3007 3646;-3006 3704;-3006 3724 1;-3006 3957;-3239 4193;-3473 4191;-4427 4191 1;-4577 4193;-4730 4107;-4814 3983 1;-4838 3944;-4880 3921;-4927 3921 1;-4972 3921;-5013 3944;-5038 3983 1;-5122 4107;-5274 4191;-5421 4191;-6377 4191 1;-6533 4191;-6696 4099;-6777 3962 1;-6796 3926;-6833 3900;-6875 3894 1;-6916 3889;-6958 3902;-6988 3932 1;-7021 3966;-7059 3996;-7101 4016 1;-7101 4017;-7104 4016;-7104 4016 1;-7191 4059;-7278 4092;-7384 4124 1;-7489 4157;-7592 4178;-7704 4195 1;-7714 4197;-7722 4199;-7729 4199 1;-7731 4201;-7733 4202;-7735 4204 1;-7849 4227;-7966 4240;-8088 4254 1;-8221 4267;-8355 4279;-8496 4279 1;-8836 4279;-9151 4231;-9437 4120 1;-9444 4118;-9450 4114;-9461 4110 1;-9737 3998;-9980 3840;-10181 3635 1;-10185 3631;-10185 3628;-10186 3624 1;-10218 3591;-10250 3536;-10300 3470 1;-10333 3425;-10393 3404;-10450 3423 1;-10505 3440;-10541 3493;-10541 3549 1;-10541 3549;-10541 3724;-10541 3724 1;-10541 3957;-10774 4193;-11008 4191;-11961 4191 1;-12194 4193;-12427 3957;-12427 3724;-12427 1796 1;-12427 1758;-12444 1721;-12472 1697 1;-12501 1670;-12539 1658;-12577 1663 1;-12634 1670;-12689 1668;-12744 1655 1;-12809 1638;-12901 1618;-13015 1597 1;-13021 1595;-13026 1593;-13032 1592 1;-13081 1582;-13101 1582;-13086 1584 1;-13124 1578;-13164 1590;-13194 1615 1;-13224 1640;-13240 1678;-13240 1716;-13240 3724 1;-13240 3957;-13474 4193;-13707 4191;-14660 4191 1;-14893 4193;-15126 3957;-15126 3724;-15126 3532 1;-15126 3476;-15164 3423;-15218 3406 1;-15273 3387;-15335 3408;-15368 3455 1;-15420 3526;-15463 3591;-15511 3643 1;-15517 3651;-15517 3652;-15518 3656 1;-15703 3851;-15933 4002;-16189 4110 1;-16458 4224;-16748 4279;-17051 4279 1;-17346 4279;-17629 4225;-17889 4120 1;-17895 4118;-17902 4114;-17909 4112 1;-18160 4005;-18392 3849;-18580 3651 1;-18586 3643;-18587 3641;-18588 3637 1;-18776 3434;-18919 3196;-19017 2931 1;-19017 2931;-19017 2933;-19019 2927 1;-19122 2648;-19176 2350;-19176 2033 1;-19176 1718;-19123 1419;-19019 1142;-19019 1139 1;-18913 875;-18770 642;-18587 446 1;-18407 241;-18054 35;-17897 -33 1;-17894 -33;-17891 -35;-17889 -37 1;-17628 -143;-17344 -200;-17051 -200 1;-16755 -200;-16468 -143;-16206 -33 1;-15946 76;-15707 235;-15518 433 1;-15470 487;-15425 560;-15368 639 1;-15335 685;-15273 705;-15218 687 1;-15164 669;-15126 617;-15126 559;-15126 538 1;-15126 435;-15088 329;-15023 247 1;-14983 198;-14983 129;-15023 80 1;-15088 -1;-15126 -108;-15126 -211;-15126 -1586 1;-15126 -1644;-15164 -1696;-15218 -1714 1;-15273 -1733;-15335 -1712;-15368 -1666 1;-15420 -1594;-15463 -1529;-15506 -1483 1;-15508 -1478;-15511 -1474;-15517 -1465 1;-15701 -1271;-15928 -1115;-16189 -1005 1;-16463 -889;-16753 -841;-17051 -841 1;-17341 -841;-17624 -888;-17889 -995 1;-17895 -997;-17902 -1001;-17909 -1003 1;-18165 -1113;-18394 -1273;-18578 -1463 1;-18582 -1468;-18582 -1470;-18584 -1474 1;-18586 -1476;-18587 -1479;-18588 -1483 1;-18776 -1684;-18919 -1924;-19019 -2192 1;-19122 -2472;-19176 -2770;-19176 -3085 1;-19176 -3401;-19122 -3698;-19019 -3973 1;-18915 -4238;-18774 -4473;-18586 -4675 1;-18582 -4680;-18580 -4682;-18580 -4684 1;-18577 -4686;-18573 -4688;-18572 -4690 1;-18384 -4883;-18152 -5043;-17897 -5151 1;-17894 -5153;-17891 -5154;-17889 -5156 1;-17628 -5263;-17344 -5317;-17051 -5317 1;-16755 -5317;-16468 -5263;-16204 -5150 1;-15943 -5038;-15707 -4885;-15518 -4684 1;-15468 -4631;-15425 -4560;-15368 -4481 1;-15335 -4433;-15273 -4413;-15218 -4431 1;-15164 -4449;-15126 -4502;-15126 -4560 1;-15126 -4560;-15126 -4648;-15126 -4648 1;-15126 -4840;-14978 -5038;-14794 -5093 1;-14694 -5123;-14598 -5144;-14499 -5165 1;-14499 -5165;-14477 -5168;-14452 -5173 1;-14340 -5198;-14217 -5219;-14085 -5240 1;-13922 -5266;-13842 -5266;-13682 -5281 1;-13547 -5294;-13415 -5306;-13286 -5306 1;-12964 -5306;-12660 -5253;-12380 -5145 1;-12373 -5143;-12371 -5143;-12369 -5143 1;-12101 -5041;-11864 -4883;-11665 -4681 1;-11657 -4671;-11653 -4668;-11649 -4665 1;-11536 -4548;-11441 -4412;-11358 -4260 1;-11334 -4218;-11289 -4192;-11242 -4192 1;-11193 -4192;-11148 -4218;-11125 -4260 1;-11028 -4434;-10923 -4593;-10791 -4726 1;-10600 -4917;-10372 -5065;-10128 -5165 1;-10125 -5165;-10124 -5166;-10118 -5168 1;-9872 -5263;-9613 -5317;-9350 -5317 1;-8783 -5317;-8251 -5120;-7882 -4730 1;-7846 -4691;-7812 -4641;-7767 -4581 1;-7733 -4538;-7676 -4519;-7622 -4536 1;-7569 -4553;-7532 -4600;-7529 -4656 1;-7526 -4846;-7376 -5039;-7192 -5093 1;-6999 -5148;-6777 -5186;-6518 -5226 1;-6513 -5227;-6510 -5229;-6505 -5231 1;-6226 -5276;-5933 -5306;-5630 -5306 1;-5305 -5306;-5020 -5259;-4754 -5153 1;-4499 -5054;-4271 -4908;-4106 -4706 1;-3948 -4513;-3839 -4282;-3777 -4034 1;-3719 -3803;-3694 -3557;-3694 -3294;-3694 -1395 1;-3694 -1161;-3927 -927;-4160 -927;-5113 -927 1;-5263 -927;-5419 -1011;-5502 -1136 1;-5525 -1174;-5569 -1198;-5613 -1198 1;-5660 -1198;-5701 -1174;-5727 -1136 1;-5808 -1012;-5960 -927;-6110 -927;-7063 -927 1;-7220 -929;-7380 -1021;-7459 -1158 1;-7479 -1194;-7516 -1219;-7558 -1224 1;-7599 -1231;-7641 -1216;-7671 -1186 1;-7706 -1151;-7744 -1121;-7790 -1100 1;-7898 -1046;-7976 -1023;-8071 -995 1;-8178 -963;-8281 -942;-8392 -924 1;-8400 -923;-8409 -921;-8417 -920 1;-8419 -918;-8419 -916;-8421 -916 1;-8527 -894;-8644 -874;-8775 -861 1;-8917 -846;-9054 -841;-9183 -841 1;-9523 -841;-9837 -888;-10125 -999 1;-10132 -1003;-10138 -1004;-10148 -1010 1;-10205 -1033;-10261 -1066;-10333 -1102 1;-10380 -1126;-10438 -1119;-10478 -1085 1;-10520 -1051;-10537 -996;-10520 -944 1;-10481 -826;-10453 -709;-10453 -616 1;-10453 -441;-10525 -246;-10637 -67 1;-10667 -20;-10665 40;-10633 84 1;-10575 164;-10541 262;-10541 359;-10541 559 1;-10541 617;-10505 669;-10450 687 1;-10393 705;-10333 685;-10300 639 1;-10233 547;-10171 461;-10103 392 1;-9914 202;-9685 53;-9442 -45 1;-9439 -46;-9435 -48;-9433 -50 1;-9432 -50;-9431 -50;-9429 -50 1;-9183 -144;-8927 -200;-8662 -200 1;-8096 -200;-7562 -1;-7194 386;-7194 386 1;-7192 387;-7194 385;-7194 388 1;-7192 392;-7192 389;-7192 390;-7143 453;-7079 538 1;-7046 581;-6988 598;-6935 581 1;-6882 566;-6846 519;-6843 463 1;-6837 273;-6688 79;-6505 25 1;-6313 -30;-6091 -67;-5824 -110 1;-5540 -156;-5246 -186;-4944 -186 1;-4619 -186;-4332 -142;-4066 -35 1;-3813 64;-3584 211;-3419 414 1;-3404 432;-3387 477;-3347 534 1;-3315 585;-3254 609;-3195 590 1;-3139 574;-3101 519;-3103 459 1;-3103 459;-3103 -482;-3103 -482 1;-3103 -693;-2915 -908;-2706 -941;-1753 -1091 1;-1501 -1129;-1215 -886;-1215 -633;-1215 -241 1;-1215 -166;-1155 -108;-1082 -108;-537 -108 1;-323 -106;-109 82;-79 292 1;-70 342;-35 384;11 399 1;60 415;111 402;147 367 1;333 190;549 49;786 -47 1;1037 -144;1294 -200;1559 -200 1;2126 -200;2658 -1;3027 388 1;3144 513;3239 654;3317 805 1;3338 848;3383 875;3432 875 1;3481 876;3526 852;3550 808 1;3642 654;3737 510;3853 392 1;4045 202;4273 53;4521 -47;4521 -47 1;4521 -48;4520 -46;4522 -47 1;4529 -50;4527 -50;4527 -50 1;4773 -144;5031 -200;5295 -200 1;5861 -200;6394 -1;6763 388 1;6802 432;6839 480;6882 538 1;6914 581;6969 600;7022 585 1;7074 572;7112 529;7119 476 1;7140 310;7271 152;7427 97 1;7615 32;7831 -23;8080 -81 1;8085 -82;8083 -82;8083 -82 1;8360 -146;8654 -178;8965 -178 1;9028 -178;9099 -173;9168 -166 1;9182 -165;9190 -163;9205 -161 1;9278 -156;9347 -148;9415 -136 1;9437 -133;9445 -133;9447 -133 1;9507 -125;9570 -116;9635 -103 1;9681 -95;9728 -112;9758 -146 1;9788 -181;9800 -230;9785 -274 1;9745 -394;9718 -512;9718 -616 1;9718 -878;9838 -1186;10043 -1369 1;10048 -1372;10051 -1374;10058 -1380 1;10243 -1538;10508 -1644;10751 -1644 1;10994 -1644;11257 -1542;11452 -1373 1;11458 -1367;11460 -1365;11466 -1364 1;11671 -1177;11789 -869;11789 -616 1;11789 -441;11717 -246;11606 -67 1;11576 -18;11579 44;11619 94 1;11644 132;11678 151;11716 155 1;11753 159;11791 147;11817 122 1;11871 77;11935 44;12001 25 1;12194 -30;12416 -67;12682 -110 1;12967 -156;13260 -186;13564 -186 1;13889 -186;14173 -142;14439 -35 1;14695 64;14923 211;15088 414 1;15181 529;15253 669;15316 817 1;15337 863;15381 893;15431 897 1;15481 900;15529 874;15555 830 1;15641 673;15739 530;15862 404 1;16061 212;16299 65;16570 -35 1;16849 -140;17147 -186;17457 -186 1;17585 -186;17713 -174;17847 -161 1;17854 -161;17842 -163;17865 -161 1;17990 -153;18110 -138;18237 -120 1;18355 -103;18475 -82;18593 -58 1;18605 -52;18617 -50;18628 -50 1;18743 -26;18848 -1;18940 25 1;19124 80;19273 279;19273 472;19273 3299 1;19273 3915;19111 4466;18724 4844 1;18718 4850;18716 4852;18709 4858 1;18305 5243;17742 5390;17090 5390 18;-1305 3799 1;-1102 3799;-928 3780;-787 3748 1;-646 3712;-518 3673;-404 3626;-539 2884 1;-627 2918;-728 2946;-838 2966 1;-945 2984;-1050 2993;-1151 2993 1;-1365 2993;-1508 2933;-1581 2813 1;-1648 2694;-1683 2535;-1683 2333;-1683 1150;-539 1150;-539 357;-1683 357;-1683 -634;-2636 -481;-2636 2346 1;-2636 2565;-2618 2763;-2579 2941 1;-2536 3121;-2463 3274;-2361 3402 1;-2259 3526;-2123 3624;-1951 3696 1;-1781 3764;-1566 3799;-1305 3799 18;10752 -52 1;10906 -52;11038 -101;11149 -200 1;11264 -303;11323 -441;11323 -616 1;11323 -791;11264 -927;11149 -1026 1;11038 -1128;10906 -1179;10752 -1179 1;10600 -1179;10465 -1128;10350 -1026 1;10238 -927;10183 -791;10183 -616 1;10183 -441;10238 -303;10350 -200 1;10465 -101;10600 -52;10752 -52 18;10279 3722;11233 3722;11233 357;10279 357;10279 3722 18;-11963 3722;-11009 3722;-11009 357;-11963 357;-11963 3722 18;7581 3722;8534 3722;8534 1150 1;8575 1137;8637 1126;8718 1118 1;8804 1105;8877 1098;8937 1098 1;9069 1098;9191 1112;9306 1137 1;9424 1158;9523 1180;9608 1201;9768 414 1;9717 392;9655 375;9583 363 1;9510 345;9437 333;9365 325 1;9292 312;9220 303;9146 299 1;9075 290;9013 286;8962 286 1;8677 286;8415 314;8182 369 1;7950 420;7750 476;7581 536;7581 3722 18;12129 3722;13082 3722;13082 1125 1;13142 1115;13210 1110;13287 1105 1;13363 1097;13435 1092;13504 1092 1;13725 1092;13876 1156;13958 1285 1;14039 1411;14080 1630;14080 1937;14080 3722;15033 3722;15033 1821 1;15033 1592;15010 1381;14963 1195 1;14916 1007;14836 845;14726 709 1;14614 572;14463 467;14272 395 1;14083 318;13847 280;13562 280 1;13280 280;13012 301;12756 344 1;12499 382;12290 425;12129 472;12129 3722 18;15729 3616 1;15737 3607;15749 3596;15758 3588 1;15784 3562;15799 3528;15799 3491 1;15799 3491;15799 3489;15799 3487;15794 3440;15767 3400 1;15769 3404;15763 3384;15737 3354 1;15711 3321;15671 3303;15623 3306 1;15549 3318;15499 3374;15499 3441 1;15499 3441;15499 3524;15499 3524 1;15501 3579;15533 3628;15585 3648 1;15634 3667;15691 3656;15729 3616 18;-14662 3722;-13708 3722;-13708 1150 1;-13667 1137;-13605 1126;-13524 1118 1;-13439 1105;-13366 1098;-13306 1098 1;-13174 1098;-13051 1112;-12936 1137 1;-12819 1158;-12719 1180;-12634 1201;-12474 414 1;-12526 392;-12587 375;-12660 363 1;-12733 345;-12806 333;-12878 325 1;-12951 312;-13022 303;-13096 299 1;-13167 290;-13229 286;-13280 286 1;-13565 286;-13827 314;-14060 369 1;-14292 420;-14492 476;-14662 536;-14662 3722 18;-6378 3722;-5425 3722;-5425 1125 1;-5365 1115;-5297 1110;-5220 1105 1;-5143 1097;-5070 1092;-5002 1092 1;-4780 1092;-4628 1156;-4549 1285 1;-4467 1411;-4427 1630;-4427 1937;-4427 3722;-3474 3722;-3474 1821 1;-3474 1592;-3497 1381;-3544 1195 1;-3591 1007;-3669 845;-3781 709 1;-3890 572;-4042 467;-4235 395 1;-4422 318;-4658 280;-4945 280 1;-5227 280;-5495 301;-5751 344 1;-6007 382;-6217 425;-6378 472;-6378 3722 18;17092 4924 1;17677 4924;18107 4790;18385 4522 1;18665 4257;18806 3849;18806 3299;18806 472 1;18722 446;18624 422;18512 402 1;18405 375;18292 354;18173 337 1;18053 320;17931 307;17809 299 1;17689 286;17572 280;17457 280 1;17187 280;16947 320;16734 402 1;16521 478;16339 589;16189 733 1;16044 878;15934 1053;15857 1259 1;15781 1458;15743 1683;15743 1930 1;15743 2424;15866 2811;16113 3087 1;16361 3361;16717 3498;17182 3498 1;17309 3498;17427 3487;17533 3466 1;17644 3441;17750 3404;17854 3357;17854 3479 1;17854 3666;17796 3819;17680 3939 1;17570 4059;17377 4119;17105 4119 1;16896 4119;16707 4101;16543 4067 1;16379 4032;16224 3986;16074 3926;15908 4725 1;16083 4785;16272 4832;16477 4867 1;16682 4905;16887 4924;17092 4924 18;1726 3810 1;1846 3810;1965 3804;2084 3793 1;2204 3779;2314 3763;2417 3741 1;2524 3724;2619 3703;2705 3677 1;2790 3651;2859 3626;2910 3601;2782 2826 1;2675 2873;2538 2912;2365 2948 1;2199 2978;2029 2993;1854 2993 1;1581 2993;1364 2934;1201 2820 1;1039 2704;947 2550;926 2353;3088 2353 1;3094 2301;3097 2245;3102 2180 1;3105 2112;3109 2050;3109 1995 1;3109 1426;2968 998;2692 709 1;2416 414;2038 267;1559 267 1;1354 267;1154 305;958 382 1;766 459;596 572;446 722 1;298 870;177 1058;81 1285 1;-9 1507;-52 1766;-52 2065 1;-52 2311;-19 2542;49 2756 1;123 2969;231 3154;376 3312 1;524 3466;712 3588;933 3677 1;1159 3765;1422 3810;1726 3810 18;-8496 3810 1;-8376 3810;-8257 3804;-8137 3793 1;-8017 3779;-7908 3763;-7804 3741 1;-7697 3724;-7603 3703;-7516 3677 1;-7431 3651;-7363 3626;-7311 3601;-7440 2826 1;-7546 2873;-7684 2912;-7855 2948 1;-8022 2978;-8193 2993;-8368 2993 1;-8640 2993;-8857 2934;-9020 2820 1;-9182 2704;-9273 2550;-9296 2353;-7132 2353 1;-7128 2301;-7124 2245;-7119 2180 1;-7116 2112;-7113 2050;-7113 1995 1;-7113 1426;-7252 998;-7529 709 1;-7806 414;-8184 267;-8662 267 1;-8867 267;-9067 305;-9264 382 1;-9455 459;-9625 572;-9775 722 1;-9923 870;-10045 1058;-10140 1285 1;-10230 1507;-10273 1766;-10273 2065 1;-10273 2311;-10240 2542;-10171 2756 1;-10098 2969;-9990 3154;-9845 3312 1;-9696 3466;-9510 3588;-9288 3677 1;-9062 3765;-8798 3810;-8496 3810 18;-12484 -146 1;-12454 -181;-12442 -230;-12457 -274 1;-12497 -394;-12524 -512;-12524 -616 1;-12524 -619;-12502 -670;-12491 -753 1;-12484 -794;-12496 -836;-12524 -866 1;-12554 -896;-12594 -911;-12640 -905 1;-12765 -882;-12886 -866;-13002 -866 1;-13009 -866;-13043 -876;-13102 -878 1;-13139 -879;-13174 -866;-13199 -841 1;-13225 -814;-13240 -781;-13240 -745 1;-13240 -745;-13240 -300;-13240 -300 1;-13240 -230;-13188 -171;-13119 -166 1;-13079 -161;-13064 -165;-13074 -166;-13056 -164;-13037 -161 1;-12964 -156;-12895 -148;-12827 -136 1;-12806 -133;-12797 -133;-12795 -133;-12795 -132;-12793 -132;-12795 -133 1;-12735 -125;-12673 -116;-12607 -103 1;-12561 -95;-12514 -112;-12484 -146 18;-14662 -213;-13708 -213;-13708 -1479 1;-13602 -1432;-13492 -1395;-13377 -1371 1;-13261 -1346;-13137 -1333;-13006 -1333 1;-12765 -1333;-12556 -1376;-12373 -1461 1;-12189 -1546;-12034 -1666;-11911 -1819 1;-11788 -1972;-11694 -2156;-11629 -2368 1;-11566 -2582;-11535 -2819;-11535 -3078 1;-11535 -3348;-11574 -3591;-11657 -3808 1;-11732 -4027;-11846 -4210;-11995 -4358 1;-12144 -4513;-12328 -4630;-12544 -4711 1;-12763 -4796;-13009 -4838;-13287 -4838 1;-13402 -4838;-13524 -4833;-13652 -4819 1;-13776 -4811;-13898 -4798;-14022 -4781 1;-14142 -4765;-14257 -4743;-14369 -4716 1;-14478 -4697;-14576 -4673;-14662 -4646;-14662 -213 18;-17051 3810 1;-16800 3810;-16574 3769;-16373 3684 1;-16168 3598;-15993 3479;-15848 3324 1;-15703 3168;-15593 2980;-15517 2763 1;-15440 2540;-15401 2298;-15401 2033 1;-15401 1768;-15442 1526;-15523 1310 1;-15603 1092;-15716 906;-15861 754 1;-16006 600;-16182 480;-16386 395 1;-16586 310;-16808 267;-17051 267 1;-17291 267;-17512 310;-17717 395 1;-17917 480;-18092 600;-18242 754 1;-18387 906;-18502 1092;-18587 1310 1;-18669 1526;-18708 1768;-18708 2033 1;-18708 2298;-18669 2540;-18587 2763 1;-18505 2980;-18392 3168;-18247 3324 1;-18102 3479;-17931 3598;-17729 3684 1;-17525 3769;-17299 3810;-17051 3810 18;5463 3810 1;5581 3810;5701 3804;5821 3793 1;5939 3779;6051 3763;6152 3741 1;6259 3724;6356 3703;6441 3677 1;6526 3651;6594 3626;6646 3601;6518 2826 1;6411 2873;6272 2912;6103 2948 1;5936 2978;5765 2993;5590 2993 1;5318 2993;5100 2934;4938 2820 1;4775 2704;4683 2550;4663 2353;6826 2353 1;6829 2301;6834 2245;6837 2180 1;6843 2112;6844 2050;6844 1995 1;6844 1426;6706 998;6428 709 1;6151 414;5773 267;5297 267 1;5091 267;4891 305;4695 382 1;4503 459;4332 572;4183 722 1;4033 870;3911 1058;3819 1285 1;3729 1507;3684 1766;3684 2065 1;3684 2311;3719 2542;3787 2756 1;3858 2969;3967 3154;4112 3312 1;4262 3466;4446 3588;4668 3677 1;4895 3765;5160 3810;5463 3810 18;-1065 2521 1;-1018 2518;-969 2518;-911 2508 1;-910 2508;-909 2506;-907 2505 1;-830 2489;-762 2473;-704 2450 1;-702 2450;-700 2450;-698 2450 1;-670 2439;-642 2426;-612 2422 1;-545 2409;-500 2350;-503 2283 1;-509 2203;-520 2131;-520 2067 1;-520 1973;-502 1875;-490 1763 1;-487 1725;-500 1688;-525 1660 1;-550 1633;-586 1616;-623 1616;-1106 1616 1;-1170 1630;-1217 1687;-1215 1750;-1215 2333 1;-1215 2360;-1211 2386;-1206 2405 1;-1198 2474;-1136 2527;-1065 2521 18;-11490 -52 1;-11336 -52;-11204 -101;-11093 -200 1;-10978 -303;-10920 -441;-10920 -616 1;-10920 -791;-10978 -927;-11093 -1026 1;-11204 -1128;-11336 -1179;-11490 -1179 1;-11642 -1179;-11777 -1128;-11893 -1026 1;-12004 -927;-12059 -791;-12059 -616 1;-12059 -441;-12004 -303;-11893 -200 1;-11777 -101;-11642 -52;-11490 -52 18;-17051 -1307 1;-16800 -1307;-16574 -1349;-16373 -1434 1;-16168 -1521;-15993 -1639;-15848 -1794 1;-15703 -1951;-15593 -2139;-15517 -2355 1;-15440 -2579;-15401 -2820;-15401 -3085 1;-15401 -3350;-15442 -3591;-15523 -3808 1;-15603 -4027;-15716 -4211;-15861 -4365 1;-16006 -4518;-16182 -4638;-16386 -4723 1;-16586 -4808;-16808 -4851;-17051 -4851 1;-17291 -4851;-17512 -4808;-17717 -4723 1;-17917 -4638;-18092 -4518;-18242 -4365 1;-18387 -4211;-18502 -4027;-18587 -3808 1;-18669 -3591;-18708 -3350;-18708 -3085 1;-18708 -2820;-18669 -2579;-18587 -2355 1;-18505 -2139;-18392 -1951;-18247 -1794 1;-18102 -1639;-17931 -1521;-17729 -1434 1;-17525 -1349;-17299 -1307;-17051 -1307 18;-7064 -1395;-6112 -1395;-6112 -3993 1;-6052 -4004;-5983 -4008;-5907 -4013 1;-5830 -4021;-5759 -4027;-5690 -4027 1;-5468 -4027;-5317 -3961;-5235 -3833 1;-5155 -3707;-5113 -3488;-5113 -3182;-5113 -1395;-4160 -1395;-4160 -3296 1;-4160 -3527;-4183 -3737;-4230 -3923 1;-4277 -4111;-4357 -4273;-4467 -4410 1;-4579 -4547;-4730 -4652;-4921 -4723 1;-5110 -4800;-5347 -4838;-5631 -4838 1;-5913 -4838;-6181 -4818;-6438 -4774 1;-6694 -4736;-6903 -4693;-7064 -4646;-7064 -1395 18;-11099 -1644 1;-11068 -1689;-11067 -1748;-11095 -1794 1;-11120 -1834;-11128 -1842;-11120 -1827 1;-11143 -1872;-11189 -1899;-11242 -1899 1;-11246 -1897;-11251 -1895;-11258 -1894 1;-11298 -1887;-11332 -1862;-11353 -1827 1;-11358 -1822;-11364 -1814;-11375 -1799 1;-11394 -1761;-11396 -1718;-11379 -1679 1;-11362 -1639;-11328 -1611;-11287 -1602 1;-11257 -1596;-11240 -1594;-11242 -1594 1;-11188 -1581;-11133 -1601;-11099 -1644 18;-9182 -1307 1;-9063 -1307;-8944 -1314;-8824 -1326 1;-8706 -1339;-8594 -1356;-8492 -1378 1;-8385 -1395;-8289 -1416;-8204 -1440 1;-8119 -1468;-8051 -1493;-7999 -1517;-8127 -2292 1;-8234 -2246;-8372 -2205;-8542 -2171 1;-8708 -2141;-8881 -2126;-9055 -2126 1;-9327 -2126;-9545 -2184;-9707 -2299 1;-9870 -2413;-9961 -2569;-9982 -2766;-7819 -2766 1;-7816 -2817;-7810 -2873;-7808 -2939 1;-7803 -3007;-7801 -3069;-7801 -3123 1;-7801 -3692;-7939 -4120;-8217 -4410 1;-8494 -4705;-8872 -4851;-9349 -4851 1;-9553 -4851;-9754 -4813;-9950 -4736 1;-10141 -4660;-10314 -4547;-10462 -4396 1;-10611 -4248;-10733 -4060;-10827 -3833 1;-10917 -3612;-10962 -3352;-10962 -3054 1;-10962 -2807;-10926 -2575;-10858 -2362 1;-10787 -2149;-10678 -1964;-10533 -1806 1;-10383 -1652;-10198 -1530;-9976 -1440 1;-9750 -1352;-9485 -1307;-9182 -1307 18;16428 5964 1;15493 5816;15156 5633;14905 5136 1;14842 5010;14767 4893;14739 4875 1;14686 4843;13829 4769;13588 4777 1;13511 4779;12673 4786;11726 4791;10003 4801;9412 4491;8810 4801;8189 4815 1;7703 4826;7501 4814;7261 4759 1;6957 4690;6950 4690;6521 4785 1;6170 4863;5974 4881;5488 4880;5457 4880 1;4811 4880;4563 4831;4074 4600 1;3912 4524;3745 4461;3703 4461 1;3660 4461;3540 4504;3437 4556 1;2881 4838;1858 4973;1148 4859 1;1005 4835;741 4765;560 4703 1;206 4579;201 4579;-280 4737 1;-640 4854;-1173 4915;-1564 4883 1;-1876 4858;-2085 4806;-2522 4644 1;-2687 4583;-2700 4585;-2962 4691 1;-3221 4796;-3260 4801;-3912 4799 1;-4286 4797;-4700 4791;-4832 4785 1;-4964 4779;-5368 4786;-5729 4802 1;-6286 4827;-6433 4820;-6697 4760 1;-7003 4690;-7012 4690;-7420 4779 1;-8263 4964;-9117 4926;-9699 4679 1;-10091 4513;-10177 4511;-10482 4666;-10748 4801;-12238 4801;-12541 4645;-12844 4489;-13138 4645;-13432 4801;-14922 4801;-15208 4663 1;-15529 4507;-15467 4502;-16152 4744 1;-16831 4984;-17621 4945;-18238 4642 1;-19010 4261;-19482 3685;-19691 2865 1;-19908 2013;-19801 1156;-19391 468 1;-19227 194;-19067 14;-18762 -238 1;-18460 -488;-18462 -552;-18772 -793 1;-19030 -993;-19347 -1393;-19507 -1720 1;-19700 -2113;-19789 -2552;-19789 -3099 1;-19788 -3688;-19727 -3966;-19489 -4450 1;-19192 -5057;-18572 -5590;-17912 -5806 1;-17374 -5984;-16546 -5988;-15770 -5633;-15447 -5485;-15239 -5576 1;-14740 -5794;-14092 -5908;-13352 -5909 1;-12569 -5909;-12118 -5779;-11532 -5381 1;-11433 -5314;-11315 -5259;-11270 -5259 1;-11225 -5259;-11047 -5352;-10875 -5465 1;-10015 -6029;-9078 -6079;-8023 -5616;-7813 -5524;-7443 -5648 1;-6638 -5917;-5482 -5996;-4840 -5824 1;-4236 -5663;-3768 -5339;-3467 -4873 1;-3148 -4378;-3090 -4073;-3064 -2779 1;-3052 -2196;-3026 -1687;-3006 -1649 1;-2959 -1560;-2787 -1559;-2312 -1644 1;-2114 -1679;-1835 -1709;-1691 -1709 1;-1229 -1712;-888 -1486;-654 -1024 1;-541 -799;-528 -788;-245 -681 1;187 -519;243 -518;668 -662 1;965 -763;1135 -795;1448 -809 1;2091 -837;2566 -704;3131 -337 1;3264 -250;3400 -179;3432 -179 1;3464 -179;3619 -259;3777 -358 1;4137 -581;4287 -644;4688 -741 1;5298 -888;5896 -821;6519 -534;6870 -372;7177 -478 1;7625 -633;8076 -733;8550 -781 1;9020 -829;9105 -876;9182 -1133 1;9308 -1554;9694 -1943;10095 -2129 1;10456 -2299;11045 -2279;11428 -2095 1;11880 -1878;12170 -1593;12329 -1108 1;12441 -766;12455 -756;12815 -779 1;14010 -855;14639 -730;15238 -297 1;15327 -232;15435 -179;15479 -179 1;15522 -179;15686 -258;15843 -355 1;16603 -824;17454 -922;18651 -679 1;19204 -567;19417 -469;19628 -230 1;19900 79;19908 145;19908 1951;19908 2068 1;19908 3651;19886 3934;19718 4401 1;19503 5000;19140 5402;18544 5703 1;18007 5974;17155 6079;16428 5964 18;17928 5561 1;18700 5363;19232 4845;19456 4071 1;19512 3877;19525 3576;19538 2141 1;19550 942;19541 396;19509 289 1;19438 50;19214 -170;18973 -238 1;18265 -438;17233 -498;16751 -367 1;16348 -257;15993 -62;15706 208;15444 456;15306 271 1;15116 17;14791 -194;14388 -327 1;14080 -428;13997 -439;13508 -436 1;13048 -433;12442 -364;12083 -274 1;12000 -253;11998 -259;12035 -436 1;12080 -647;12030 -945;11908 -1199 1;11636 -1762;10897 -2045;10292 -1817 1;9806 -1635;9468 -1148;9468 -632;9468 -407;9216 -431 1;8866 -464;8256 -399;7783 -280 1;7323 -163;7201 -108;7046 57;6934 175;6772 37 1;5907 -704;4382 -591;3607 271;3424 474;3360 377 1;3119 21;2522 -336;2023 -420 1;1440 -518;756 -394;341 -114;129 29;28 -91 1;-139 -289;-354 -379;-661 -379;-932 -379;-932 -509 1;-933 -750;-1017 -955;-1187 -1124 1;-1437 -1374;-1550 -1391;-2246 -1283 1;-2569 -1232;-2887 -1163;-2953 -1129 1;-3248 -975;-3372 -718;-3372 -258;-3372 65;-3550 -58 1;-3801 -230;-4065 -337;-4405 -402 1;-4781 -475;-5094 -474;-5671 -398 1;-6502 -289;-6766 -202;-6943 24;-7040 149;-7232 3 1;-7499 -201;-7690 -292;-8042 -381 1;-8755 -564;-9576 -395;-10120 47 1;-10278 175;-10291 178;-10328 108 1;-10358 53;-10348 -23;-10289 -176 1;-10246 -291;-10206 -465;-10202 -563 1;-10196 -705;-10182 -736;-10133 -716 1;-9610 -509;-8452 -550;-7836 -799 1;-7626 -884;-7587 -889;-7532 -839 1;-7372 -694;-7184 -659;-6575 -659;-6548 -659 1;-5984 -659;-5837 -684;-5685 -810 1;-5627 -859;-5602 -854;-5492 -772 1;-5374 -686;-5322 -678;-4739 -666 1;-4055 -652;-3888 -680;-3692 -845 1;-3432 -1064;-3432 -1066;-3434 -2479 1;-3436 -3540;-3448 -3805;-3503 -4029 1;-3693 -4791;-4168 -5277;-4922 -5483 1;-5261 -5575;-6112 -5566;-6698 -5463 1;-7272 -5363;-7461 -5289;-7610 -5109;-7726 -4968;-7879 -5088 1;-8814 -5825;-10355 -5685;-11073 -4798;-11235 -4596;-11494 -4860 1;-11783 -5155;-12156 -5370;-12572 -5482 1;-13108 -5626;-14450 -5523;-14960 -5299 1;-15058 -5256;-15175 -5160;-15239 -5069;-15350 -4913;-15611 -5103 1;-16440 -5704;-17556 -5733;-18389 -5176 1;-18763 -4926;-18970 -4689;-19174 -4279 1;-19544 -3536;-19541 -2623;-19167 -1859 1;-18698 -903;-17669 -417;-16549 -623 1;-16267 -675;-15788 -888;-15574 -1057;-15421 -1179;-15405 -589 1;-15394 -169;-15373 26;-15332 89 1;-15235 239;-15319 237;-15504 86 1;-16274 -546;-17402 -634;-18285 -132 1;-19617 624;-19853 2734;-18732 3863 1;-17912 4689;-16505 4772;-15566 4050;-15379 3907;-15333 4019 1;-15270 4170;-15105 4323;-14923 4399 1;-14712 4487;-13672 4487;-13461 4399 1;-13264 4317;-13137 4195;-13048 4001 1;-12982 3860;-12974 3728;-12973 2871;-12973 2823 1;-12972 1843;-12978 1874;-12782 1926;-12692 1950 1;-12692 3973;-12680 4038;-12439 4250 1;-12222 4440;-12067 4471;-11387 4455 1;-10804 4441;-10780 4438;-10624 4329 1;-10492 4238;-10413 4134;-10306 3908 1;-10303 3901;-10213 3963;-10106 4044 1;-9632 4408;-9047 4566;-8312 4528 1;-7825 4503;-7365 4416;-7096 4297 1;-6933 4226;-6914 4225;-6848 4284 1;-6702 4417;-6483 4457;-5908 4459 1;-5355 4461;-5138 4426;-5010 4317 1;-4958 4272;-4918 4279;-4753 4362 1;-4571 4454;-4518 4461;-3955 4460 1;-3267 4459;-3106 4414;-2910 4168;-2797 4027;-2623 4147 1;-2311 4362;-2052 4456;-1635 4505 1;-1021 4577;-348 4454;37 4200;186 4101;437 4238 1;800 4435;1069 4503;1588 4529 1;1962 4547;2134 4535;2508 4464 1;3072 4358;3355 4230;3495 4017 1;3552 3931;3607 3861;3617 3861 1;3627 3861;3710 3925;3802 4004 1;4053 4219;4484 4414;4868 4487 1;5440 4594;6391 4505;6861 4299;7033 4223;7198 4332 1;7357 4438;7382 4441;8005 4453 1;8611 4465;8658 4460;8826 4373 1;8923 4323;9058 4212;9126 4127;9248 3974;9260 2937;9272 1901;9360 1902 1;9541 1903;9543 1914;9556 2969;9568 3974;9690 4127 1;9758 4212;9892 4322;9989 4371 1;10149 4453;10221 4461;10767 4460 1;11260 4459;11397 4446;11528 4387 1;11682 4317;11694 4317;11848 4387 1;11979 4446;12117 4459;12611 4460 1;13162 4461;13230 4453;13396 4369;13577 4278;13732 4359 1;13871 4432;13961 4441;14551 4441;15214 4441;15197 4626 1;15173 4869;15240 5059;15408 5233 1;15568 5397;15799 5483;16366 5586 1;16835 5672;17538 5661;17928 5561;17928 5561 18;-13184 -2139 1;-13282 -2139;-13381 -2152;-13479 -2177 1;-13572 -2202;-13648 -2234;-13708 -2274;-13708 -3993 1;-13662 -4004;-13602 -4008;-13530 -4013 1;-13457 -4021;-13379 -4027;-13293 -4027 1;-13032 -4027;-12837 -3936;-12704 -3756 1;-12572 -3582;-12506 -3348;-12506 -3054 1;-12506 -2443;-12733 -2139;-13184 -2139 18;-13248 -2631 1;-13034 -2631;-12976 -2876;-12976 -3090 1;-12976 -3284;-13054 -3505;-13248 -3506;-13248 -2631 18;17360 2730 1;16930 2730;16714 2463;16714 1930 1;16714 1675;16776 1464;16900 1297 1;17024 1130;17212 1047;17464 1047 1;17548 1047;17623 1052;17687 1060 1;17750 1065;17807 1072;17854 1080;17854 2603 1;17794 2636;17720 2666;17636 2691 1;17550 2718;17459 2730;17360 2730 18;17409 2232;17409 1571 1;17201 1492;17180 1713;17180 1926 1;17178 2120;17192 2338;17409 2232 18;69180 53168 1;69435 53137;69705 53115;70028 53115 1;71160 53123;71678 53512;72750 53895 1;73958 54345;74580 54570;75870 54750 1;76800 54893;77460 54863;78090 55575 1;78675 56250;79028 56685;79148 57570 1;79200 58012;79260 58245;79185 58673 1;79065 59325;79095 59670;79230 60315 1;79320 60802;79320 61162;79725 61433 1;80370 61875;80768 62205;81548 62130 1;82448 62063;82815 61500;83730 61515 1;84795 61530;85328 61635;86408 61613 1;87367 61605;87908 61455;88725 60930 1;89160 60660;89250 60270;89265 59753 1;89280 59250;89115 58995;88830 58575 1;88418 58005;88110 57802;87585 57330 1;86760 56610;86265 56325;85568 55470 1;84998 54810;84548 54585;84165 53790 1;83798 53055;83708 52620;83625 51795 1;83505 50700;83175 50190;82770 49170 1;81855 46980;81068 46020;80310 43770 1;80055 43050;79905 42570;80227 41873 1;80288 41738;80348 41610;80408 41490;69210 50662 1;70268 50715;70867 50573;71850 50992 1;72825 51435;73275 51742;74310 52073 1;75188 52373;75645 52485;76530 52815 1;77227 53085;77828 53085;78390 52575 1;78795 52200;78720 51780;78750 51210 1;78780 50302;78600 49815;78165 48990 1;77678 48090;77310 47700;76905 46755 1;76178 45053;75780 44130;75727 42270 1;75690 41213;75803 40545;75938 39488;69210 46020 1;69480 45923;69705 45750;69908 45450 1;70110 45150;70200 44963;70208 44595 1;70215 44025;70005 43755;69870 43193 1;69675 42525;69518 42135;69218 41603;89265 73830 1;89040 73545;88575 73223;88387 73530 1;88178 73875;88058 74242;88350 74512 1;88620 74783;89025 75135;89250 74813 1;89468 74483;89520 74123;89265 73830 18;69158 62535 1;69255 62512;69360 62505;69488 62512 1;70035 62565;70418 62700;70710 63173 1;71048 63750;71025 64140;71430 64673 1;72488 66120;73155 66795;74610 67852 1;75338 68393;75878 68355;76770 68573 1;77617 68790;77977 69105;78788 69450 1;79515 69780;80025 69713;80648 70230 1;81015 70560;81278 70673;81525 71093 1;81698 71400;81885 71602;82245 71595 1;82710 71595;82890 71265;83145 70875 1;83318 70605;83408 70470;83588 70193 1;83790 69885;84240 69840;84510 70095 1;85410 70950;85808 71445;86768 72233 1;87105 72525;87135 72960;86910 73335 1;86745 73583;86655 73733;86685 74010 1;86730 74415;86895 74610;87210 74873 1;87825 75420;88005 75893;88770 76253 1;89190 76463;89550 76665;89948 76395 1;90367 76102;90660 75833;90668 75315 1;90668 74573;90218 74242;90270 73492 1;90315 72563;90398 71970;91050 71295 1;91598 70710;91830 70320;92550 69930 1;93330 69525;93885 69713;94770 69870 1;95378 69990;95700 70125;96330 70095 1;96960 70073;97320 69713;97590 69135 1;97958 68303;98130 67875;98430 66990 1;98595 66473;98895 66075;99450 66075 1;99990 66075;100260 66285;100688 66615 1;101085 66938;101325 67170;101580 67492;118417 37920 1;118410 38063;118380 38213;118328 38370 1;118087 38993;118058 39495;117465 39773 1;117158 39923;116977 39983;116648 39975 1;116085 39960;115306 39791;115276 39235 1;115216 38718;115180 38397;115188 37880 1;115188 37647;115233 37370;115285 37190 16;115709 37870 1;115822 35231;118914 37371;117405 38895 1;117106 39197;116122 39241;115920 38864 1;115769 38587;115717 38117;115709 37870 18;69150 64305 1;69563 64448;69893 64695;70290 65070 1;71025 65813;71355 66225;72090 66975 1;72727 67643;73020 68003;73748 68573 1;74280 69000;74528 69293;75188 69495 1;76020 69765;76530 69593;77325 69953 1;78225 70373;78615 70740;79568 71055 1;80325 71310;80760 71483;81330 72053 1;81675 72413;81818 72803;82328 72810 1;82665 72825;82785 72555;82988 72270 1;83227 71933;83400 71790;83685 71475 1;83925 71190;84345 71220;84630 71475 1;85028 71850;85298 71970;85665 72390 1;85988 72773;86175 73193;85928 73613 1;85725 73950;85770 74220;85928 74573 1;86137 75060;86205 75352;86588 75735 1;86940 76110;88180 76923;88676 77100;123225 70193 1;123585 69495;123690 69105;124005 68370 1;124193 67950;124335 67598;124455 67260;124477 61650 1;124260 61403;124012 61170;123788 60810 1;123045 59693;122715 59085;121785 58110 1;120637 56925;119948 56430;118590 55492 1;117360 54660;116925 53963;115650 53213 1;114878 52785;114405 52755;113610 52395 1;113167 52215;112928 52162;112485 52012 1;112087 51885;112005 51600;111705 51315 1;111330 50970;111045 50805;110565 50738;69158 66120 1;70035 66585;70410 67028;71168 67733 1;71970 68505;72390 68873;73305 69495 1;73770 69810;74040 69930;74565 70133 1;75637 70553;76268 70575;77227 71213 1;77985 71730;78495 71745;79365 72030 1;79680 72150;79800 72315;80048 72533 1;80430 72893;80588 73170;81090 73350 1;81578 73545;81795 73800;82328 73815 1;82755 73830;83010 73635;83288 73290 1;83558 72960;83580 72653;83970 72450 1;84420 72225;84930 72690;85005 73193 1;85065 73695;85080 73950;85028 74453 1;84990 74790;85178 74955;85365 75233 1;85695 75765;85808 76080;86288 76470 1;86820 76920;87038 77250;87690 77490 1;88125 77670;88448 77843;88793 77963;90428 77963 1;90945 77745;91283 77288;91710 76733 1;92460 75750;92745 75113;92887 73875 1;92977 72975;93375 72473;94148 71970 1;94358 71843;94530 71895;94785 71895 1;95528 71903;96098 72030;96750 71655 1;97215 71385;97425 71280;97770 70830 1;98137 70335;98460 70193;98805 69653 1;99368 68835;99630 69180;99870 69533 1;100455 70170;100815 70373;101430 70890 1;101970 71370;102398 71385;103065 71655 1;103935 72023;104408 72150;105345 72315 1;106118 72450;106598 72690;107310 72352 1;107962 72120;108308 71955;109005 71963 1;110018 71985;110655 71970;111465 72578 1;111870 72893;111953 73185;112148 73658 1;112230 73867;112245 74010;112470 74190;112470 74190 1;113730 74700;114465 74805;115830 74730 1;116505 74700;116917 74760;117525 74430;118403 72773 1;118950 72383;119340 71955;119962 71685 1;120623 71408;121058 71445;121762 71258 1;122370 71100;122663 70973;123218 70665 1;123818 70335;124102 69915;124448 69495;124485 55560 1;123878 55058;123225 54563;122370 53970 1;121335 53280;120968 52733;119910 52095 1;118748 51412;118170 51052;116910 50610 1;116258 50393;115905 50340;115230 50250 1;114735 50205;114698 49650;114225 49575 1;113220 49410;112740 49200;111727 49110 1;110265 48990;109628 48233;108172 48278 1;107595 48278;106748 48525;106005 48375 1;105525 48285;105225 48412;104805 48173 1;104108 47790;103837 47430;103087 47152 1;102420 46920;102278 46793;101768 46545;96285 77977 1;96990 77573;97290 77123;98070 76650 1;98887 76163;99315 75653;100290 75690 1;101137 75742;101528 76200;102390 76155 1;102945 76133;103215 75900;103785 75930 1;104325 75975;104587 76080;105105 76230 1;105990 76492;106448 76665;107370 76650 1;107730 76650;107895 76523;108270 76455 1;108525 76365;108503 76088;108503 75810 1;108495 75203;108383 75188;108637 74625 1;108818 74220;109028 73823;109477 73808 1;109995 73800;110333 73733;110753 74048 1;111000 74242;111098 74400;111188 74708 1;111308 75180;111315 75158;111428 75623 1;111488 75893;111555 76155;111833 76178 1;112080 76208;112208 76193;112425 76230;102600 78008 1;102758 77933;102915 77858;103087 77775 1;103920 77370;104348 77040;105285 77010 1;106365 76980;106875 77565;107970 77475 1;108360 77453;108585 77355;108870 77070 1;109328 76613;109005 76110;109050 75450 1;109087 74745;109170 74378;109890 74378 1;110520 74393;110715 74640;110835 75262 1;110970 75998;111113 76230;111368 76928 1;111503 77310;111975 77130;112328 77333 1;112920 77685;113250 77887;113903 78038;116400 78045 1;116535 78000;116678 77940;116843 77873 1;117637 77543;118163 77310;118973 77018 1;119670 76778;119648 75585;120068 75315 1;121350 74498;122227 74490;123570 73305;112425 76230 1;113490 76433;114360 76590;115425 76770 1;116648 76995;117413 77085;118628 76575 1;118695 76545;118485 76448;118575 76178 1;119385 73665;121815 74250;123698 72578;112605 75833 1;114165 76102;115297 76320;116887 76433 1;117480 76485;117795 76463;118387 76335 1;118328 76185;118178 76020;118200 75848 1;118553 73005;121020 74085;122753 72668;112065 74940 1;112163 75173;112358 75218;112605 75270 1;113805 75465;114405 75653;115628 75735 1;116505 75803;117015 75960;117893 75833 1;117953 75750;117810 75262;117848 75165 1;118680 72945;120518 73215;122558 72225 1;123270 71880;123750 71760;124440 71588;111975 74288 1;112065 74617;112253 74805;112590 74873 1;113655 75015;114188 75180;115268 75210 1;116190 75255;116655 75352;117585 75233;124508 52380 1;123735 52012;123098 51855;122205 51315 1;121118 50670;120525 50400;119325 50010 1;118508 49762;118095 49530;117488 48930 1;116887 48360;116475 48113;115665 47955 1;113558 47558;112320 47633;110542 47483;119858 78060 1;120615 77745;121297 77460;122250 76950 1;122783 76673;122962 76275;123060 75675 1;123188 74887;123337 74242;124095 73965;124508 49733 1;124073 49598;123623 49433;123060 49223 1;121620 48720;120990 48255;119580 47700 1;117150 46785;115725 46980;113137 46980;123428 34110 1;123525 34253;123623 34410;123727 34590 1;123998 35145;124095 35565;124560 35858;124523 43883 1;124208 43995;123870 44108;123465 44250 1;122137 44723;121448 44910;120068 45150 1;119010 45345;118477 45443;117428 45615 1;117098 45675;116850 45825;116528 45893 1;116318 45953;116408 46275;116625 46290 1;116828 46320;116940 46260;117150 46290 1;118883 46223;120038 46088;121410 46133 1;122025 46148;123188 46193;123465 46313;124523 34110;124560 34193;124530 44453 1;124065 44550;123765 44648;123270 44835 1;122400 45150;121928 45195;121087 45533 1;120848 45630;120660 45720;120922 45750 1;122415 45938;123428 45938;124523 45930;123465 46313 1;123885 46530;124215 46748;124523 46957;124433 71933 1;124260 71977;124087 72023;123922 72075;124425 72308;124305 72352;69240 38070 1;70613 38243;71858 38415;73665 38580 1;75585 38760;75908 38355;77400 38415 1;79485 38505;80453 38595;82485 38850 1;83205 38948;83580 38948;84293 39120 1;85125 39330;85650 39510;86137 40215 1;86843 41258;87262 41730;88043 42720 1;88538 43365;89115 43740;89925 43770 1;93262 44070;94875 44228;98235 44820 1;99458 45098;100065 45188;101235 45660 1;102810 46215;103493 47115;105225 47160 1;107340 47220;108435 47115;110505 46620 1;112575 46125;113655 46148;115785 46050 1;118568 45930;119925 45743;122715 45630 1;123428 45608;123983 45623;124530 45593;69128 68242 1;69308 68363;69495 68490;69698 68625 1;73380 71183;74985 72203;78578 74783 1;80258 76043;81083 76725;82590 77948;103875 57915;116363 62985 1;114788 62738;112905 62512;111352 62183 1;110310 61965;108975 61800;107873 61568;74175 70159;79778 53235 1;81008 53250;82470 53730;84465 54450 1;86250 55103;87623 55125;89205 54060 1;90383 53265;91125 52838;92483 52380 1;94335 51840;95235 52020;97365 52230 1;97823 52275;98220 52320;98595 52365;109912 65477;106598 63218 32;107783 61733;107137 74783 1;107453 73980;107460 73492;107962 72773 1;108240 72375;108555 72262;109058 72233 1;109410 72225;109650 72323;109898 72367 1;110145 72405;110408 72390;110723 72488 1;111143 72645;111337 72870;111630 73208 1;111795 73410;111810 73560;111893 73808 1;111998 74175;112073 75045;112080 75405;69195 48818 1;69338 48570;69488 48308;69645 48030;83918 39030 1;84930 38970;85658 38850;86468 39465 1;87083 39945;87518 40027;88298 40005 1;89693 39975;90390 40058;91793 40110 1;93105 40162;94538 40350;95858 40320;87727 42300 1;86985 41318;88560 40088;89798 40020;102909 57261 1;100884 56076;98760 55335;96285 53693 1;95048 52890;94515 52545;93480 51938;103515 59340;69195 47918 1;69293 47955;69390 47993;69495 48030;69120 74693;69383 74865 32;69120 72308;69120 74693 18;69293 54375 1;69255 54443;69218 54510;69180 54578;98715 77992;99255 77775 32;98858 76800 32;97913 77168;98235 77992;98715 77992 18;74115 38700 1;73852 40298;73815 41198;72975 42570 1;71633 44760;70973 45870;69645 48060;79605 53550 1;77198 55988;75975 57090;73665 59610 1;72218 61185;71602 61943;70125 63480 1;69720 63908;69360 64283;69143 64733;69645 48060 1;70913 48683;71558 48938;72825 49500 1;74303 50168;75158 50332;76485 51270 1;77550 52035;78225 52238;79185 53130 1;79313 53258;79433 53378;79545 53490 33;80258 54203;80640 54742;81248 55710 1;81923 56820;82463 57270;83543 57990 1;84773 58823;85313 59393;86678 59970 1;88073 60570;88958 60750;90458 60450 1;92415 60068;93488 60255;95498 60255 1;96413 60240;96795 60195;97688 60225 1;98685 60262;99060 60270;100178 60495 1;101903 60840;102045 60870;103095 60668 1;103477 60608;103485 60668;103890 60758 1;104520 60908;104895 61207;105547 61215 1;106133 61230;106387 61253;107003 61343 1;107348 61403;107610 61485;107887 61568;74025 39420 1;74700 41183;75150 42030;76125 43650 1;76898 44948;77310 45608;78405 46650 1;79515 47723;81060 48203;82485 48810;79605 53370 1;80010 52973;80190 52755;80595 52350 1;81023 51923;81045 51555;81225 50970 1;81413 50348;81510 50040;81705 49410 1;81803 49080;81683 48878;81585 48540;69188 54360 1;69840 54495;70433 54315;70988 54293 1;71648 54278;72435 54427;72968 54353 1;73688 54262;74025 54128;75045 53910 1;76635 53610;77205 53580;79275 53310;69240 37838 1;69750 37568;70463 37065;70838 36750 1;71558 36158;73110 34868;74227 33953;76845 38490 1;77003 37665;77100 37253;77265 36420 1;77445 35460;77617 34733;77670 33960;73703 52598;75953 54615;112530 47799;103395 60720 1;103598 59880;104025 59588;104505 58860 1;105053 58035;105570 57585;105735 56595 1;105945 55515;105675 55537;104805 54780 1;104303 54345;103898 54218;103635 53610 1;103440 53190;103643 52478;104115 52440;102262 52545 1;102593 52515;102803 52537;102945 52605 33;103080 52665;103163 52762;103230 52883 33;103290 53010;103343 53160;103425 53332 33;103493 53475;103583 53633;103725 53798;69195 48825 1;69270 48660;69338 48473;69398 48248 1;69428 48113;69330 48023;69195 47955;69203 48818;69195 48825 18;124455 64207 1;123540 64485;122693 64688;121455 64710 1;119295 64755;117623 64643;116385 62880 1;115575 61740;115500 60945;115335 59550 1;114975 56640;118995 53700;122415 53370 1;123135 53295;123840 53325;124500 53430;109485 57600 1;109178 57173;108878 56655;108488 56475 1;107685 56115;106740 55845;105465 55380;113595 48600 1;113415 48825;112830 49245;112688 49433 1;112245 50010;112110 50400;112035 51248 1;111945 52110;111870 52650;112193 53370;113535 53213 1;112935 53273;112530 53220;112125 53295 1;111773 53363;111525 53528;111180 53603 1;110790 53685;110265 53655;109725 53610 1;109380 53588;109305 53512;109065 53730 1;108885 53895;108712 54030;108593 54158 1;108240 54540;107730 54405;106350 55680;112860 49238;115005 49260;95835 51690;91545 52650 1;90788 51840;90375 51375;89355 50940 1;88275 50490;87818 50070;86715 49680 1;86355 49560;86137 49650;85785 49530 1;84315 49058;84105 48900;82575 48750 1;82200 48720;81840 48983;81735 49290;77385 55830 1;77273 57983;77273 59063;77085 61200 1;77033 61733;76988 62003;77085 62520 1;77183 63052;77100 63435;77498 63795 1;78203 64463;78525 64838;79313 65415 1;80115 66015;80550 66330;81518 66585 1;82148 66758;82365 66795;83010 66623 1;83512 66495;83798 66578;84390 66615 1;85095 66668;85350 66225;85808 65580 1;86213 64995;86475 64710;86768 64035 1;87008 63473;87008 63090;87233 62588;74887 58373 1;75143 58927;75308 59235;75285 59835 1;75255 60503;75323 60840;75255 61492 1;75165 62318;75668 62707;75593 63525 1;75555 63893;75420 64073;75480 64425 1;75510 64650;75563 64845;75780 64898 1;76185 64898;76530 64665;76568 64290 1;76613 63832;76718 63525;77137 63330;78533 64695 1;78945 64065;79117 63630;79793 63270 1;80753 62760;81278 62550;82102 61830 1;82583 61410;82673 61058;82988 60495 1;83227 60060;83581 59405;83792 59083;83483 59820 1;83678 59985;83602 60262;83843 60360 1;84270 60548;84510 60660;84983 60615 1;85223 60593;85418 60555;85523 60330 1;85643 60060;85710 59918;85867 59655;85605 59430 33;85102 59137;84698 58830;84203 58463 32;84165 58665 33;83858 59010;83663 59295;83475 59603 32;83483 59820 18;86408 64755 1;86588 65775;86723 66270;86873 67290 1;86933 67740;86940 68025;86723 68415 1;86348 69075;85973 69413;86078 70155;86648 70290 1;86663 70050;86622 68946;86599 68758;109455 41640 1;108285 41723;107408 41730;106253 41693 1;105323 41670;104887 41573;103995 41760 1;103193 41933;102758 42060;101955 41910 1;99480 41468;98205 41138;95843 40290;95798 40305 1;96210 40185;96983 40110;96765 39510 1;96248 38115;95820 37373;95925 35880 1;95970 35145;96038 34575;96128 34020;115028 34088 1;115448 34245;115890 34418;116415 34650 1;116790 34823;117023 34823;117375 35040 1;117758 35295;118140 35445;118395 35820 1;118740 36345;118943 36848;118905 37283;109373 40613 1;107348 40545;106343 40582;104333 40582 1;102345 40582;101363 40418;99398 40185;96878 39855;114840 40207 1;114675 39143;114255 37838;114825 36930 1;115403 36008;115643 35573;116385 34770;80025 43350;78458 42855;81231 42023;79148 39570;75518 39030 1;76680 39015;77258 39015;78428 39015 1;78900 39015;79088 39098;79492 39360 1;80137 39810;80685 40170;81105 40628 1;82073 41640;82673 42128;83992 42585 1;84788 42870;85185 43103;85815 43673 1;86198 44025;86490 44078;86985 44235 1;87413 44385;87623 44483;88073 44588 1;88508 44700;88748 44693;89205 44670 1;90120 44640;90578 44570;91500 44622 1;94053 44791;94018 44802;97910 45470 1;99009 45659;99116 45737;100278 45985 1;100496 46037;101150 46127;101578 46202;69870 41093;74992 49965 1;75248 49643;75420 49537;75653 49185 1;75803 48953;75495 48623;75262 48465 1;74955 48278;74625 48045;74378 48300 1;74003 48698;73845 48923;73463 49305 1;73365 49403;73680 49530;73762 49425 1;73973 49140;74018 48818;74378 48765 1;74528 48750;74760 48832;74708 48975 1;74573 49328;74625 49552;74453 49875;74992 49965 18;74933 49920;74753 50310 33;75225 50520;75690 50745;76223 51098 32;76523 51090 1;76658 50985;76665 50873;76748 50715 1;76815 50573;76635 50423;76477 50400 1;76260 50378;76148 50430;75938 50400 1;75795 50385;75735 50213;75803 50085 1;76020 49673;76380 49508;76852 49545 1;77265 49590;77528 49628;77828 49920 1;77955 50055;78188 50213;78278 50040 1;78352 49890;78563 49980;78637 50137 1;78735 50363;78720 50528;78930 50655 1;79283 50880;79785 50768;80205 50753 1;80400 50753;80708 50558;80648 50363 1;80550 50078;80078 49957;79823 49785 1;79718 49725;79710 49485;79838 49485 1;79995 49485;80123 49552;80227 49425 1;80483 49103;80468 48848;80693 48495 1;80768 48375;80843 48218;80723 48135 1;80558 48037;80355 47910;80242 48060 1;80123 48218;80063 48285;79958 48435 1;79860 48578;79680 48630;79553 48525 1;78968 48075;78623 47925;77992 47550 1;77738 47408;77475 47280;77273 47475 1;77108 47640;77063 47753;76943 47940 1;76793 48173;76545 48105;76373 48300 1;75810 48930;75533 49253;74977 49875;74933 49920 18;78803 49290 1;78720 49358;78660 49350;78570 49380 1;78480 49418;78413 49343;78383 49253 1;78323 49103;78405 49012;78488 48863 1;78585 48668;78727 48623;78930 48533 1;79028 48495;79133 48615;79133 48720 1;79125 48998;78975 49117;78788 49313;78803 49290 18;69158 66180 1;69248 66180;69315 66165;69428 66150 1;69570 66143;69623 66023;69683 65880 1;69773 65655;69825 65393;70073 65400 1;70253 65408;70350 65393;70538 65370 1;70710 65355;70703 65145;70733 64965 1;70762 64748;70793 64635;70838 64410 1;70852 64305;70838 64192;70733 64155 1;70583 64117;70710 63930;70718 63780 1;70725 63608;70740 63525;70748 63345 1;70748 63188;70950 63052;70823 62955;70568 63015 33;70433 63165;70283 63315;70125 63480 1;69975 63637;70320 64200;70193 64350 1;70050 64508;69413 64328;69308 64492 1;69248 64582;69195 64673;69143 64762;69150 66188;69158 66180 18;70485 59445;70710 60015;93188 51375;81518 41640 1;81435 41843;81390 42113;81188 42060 1;80865 41993;80498 41850;80378 42150 1;80137 42713;79755 42855;79523 43410 1;79425 43635;79238 43793;79387 43980 1;79500 44138;79620 44273;79733 44430 1;79808 44550;79800 44678;79718 44790 1;79613 44940;79496 45231;79645 45328 1;79781 45426;79688 45503;79838 45585 1;79913 45638;80085 45390;80137 45300 1;80175 45218;80227 45128;80333 45135 1;80640 45180;80805 45240;81113 45165 1;81443 45090;81608 45015;81953 44985 1;82102 44978;82298 45135;82223 45270 1;82102 45480;82012 45593;82028 45825 1;82028 46005;82110 46103;82253 46200 1;82387 46305;82500 46320;82673 46275 1;82755 46260;82808 46245;82898 46260 1;83010 46290;83078 46388;83078 46500 1;83070 46635;83085 46733;83198 46800 1;83303 46875;83348 46980;83483 46965 1;83678 46950;84345 47213;84473 47063 1;84600 46912;84570 46703;84570 46500 1;84570 46305;83963 46073;83798 45960 1;83708 45908;83633 45908;83543 45945 1;83415 45998;83325 46050;83213 45990 1;83003 45893;82883 45773;82852 45540 1;82823 45345;82785 45218;82898 45045 1;82995 44895;83130 44850;83318 44865 1;83610 44895;83805 45015;84053 44850 1;84248 44723;84450 44655;84458 44415 1;84458 44183;84315 44078;84143 43920 1;83648 43500;83348 43373;82838 42975 1;82545 42758;82448 42585;82268 42270 1;82065 41925;81930 41707;81518 41640 18;90218 53325 1;90188 53130;90083 53018;90038 52823 1;90008 52710;90045 52515;90023 52395 1;89977 52200;89805 52133;89573 51930 1;89063 51495;88733 50985;88313 50460;69180 54270;69203 54233 1;69233 54150;69218 54075;69180 54000;69188 54262;69180 54270 18;69180 52860 1;69240 52785;69293 52703;69338 52582 1;69495 52080;69518 51810;69637 51293 1;69653 51233;69563 51203;69503 51188 1;69390 51165;69285 51158;69188 51158;69188 52867;69180 52860 18;69188 53783 1;69278 53768;69345 53723;69360 53655 1;69383 53573;69308 53483;69180 53423;69188 53783 18;69218 48938 1;69668 48773;69893 48683;70358 48518 1;70403 48503;70283 48480;70238 48457 1;69983 48353;69795 48398;69608 48203;69218 48938 18;74640 51518 1;74475 51690;74453 51923;74580 52043 1;74700 52155;74933 52117;75090 51938 33;75255 51773;75278 51540;75158 51427 1;75030 51308;74798 51345;74640 51518 18;71977 51068 1;71835 51150;71775 51203;71678 51323 1;71558 51473;71423 51540;71242 51503 1;71093 51473;71018 51420;70867 51427 1;70658 51443;70477 51570;70477 51773 1;70455 52373;70425 52665;70433 53258 1;70433 53408;70485 53543;70628 53558 1;70740 53573;70808 53617;70928 53588 1;71070 53558;71145 53468;71198 53318 1;71400 52740;71400 52418;71678 51863 1;71715 51787;71805 51787;71887 51818 1;72075 51893;72165 51953;72367 51998 1;72428 52020;72495 52028;72555 52012 33;72600 51998;72645 51968;72683 51908 1;72735 51810;72765 51758;72818 51653 1;72848 51593;72855 51518;72833 51457 33;72825 51420;72795 51383;72758 51353 1;72548 51240;72443 51195;72233 51082 1;72113 51030;72008 50940;71933 51023;72098 49343 1;71963 49425;71925 49508;71798 49582 1;71678 49658;71678 49883;71813 49927 1;72038 50018;72173 50040;72428 50018 1;72623 50003;72727 50010;72923 50048 1;73035 50078;73230 49995;73268 49883;72098 49343 18;72098 51908 32;71992 51870 33;71963 51855;71925 51840;71887 51818 1;71805 51787;71715 51787;71678 51863 1;71400 52418;71400 52740;71198 53318 1;71160 53408;71123 53475;71070 53528 32;71183 53558 33;71370 53543;71550 53520;71558 53332 1;71558 53265;71588 53228;71588 53153 1;71588 53040;71490 53003;71498 52883 1;71505 52770;71565 52688;71678 52643 1;71850 52575;71963 52500;72008 52313 1;72030 52177;72068 52110;72098 51983;72098 51908 50;70823 48802 32;70770 48908 33;70200 50115;69983 50858;69788 52207 1;69720 52650;69600 52927;69803 53318 1;69998 53715;70185 53887;70553 54128 32;71783 54188 32;71820 54075 33;72128 53280;72233 52830;72578 52012 32;72510 52020 33;72465 52028;72413 52020;72367 51998 1;72255 51975;72180 51953;72105 51915 32;72090 52012 33;72060 52125;72030 52193;72008 52313 1;71963 52500;71850 52575;71678 52643 1;71565 52688;71505 52770;71498 52883 1;71490 53003;71588 53040;71588 53153 1;71588 53228;71558 53265;71558 53332 1;71550 53550;71303 53543;71093 53565 32;70890 53595 33;70793 53610;70725 53573;70628 53558 1;70485 53543;70433 53408;70433 53258 1;70425 52665;70455 52373;70477 51773 32;70515 51623 33;70575 51510;70710 51443;70867 51427 1;70935 51427;70988 51435;71040 51450 32;71242 51503 33;71423 51540;71558 51473;71678 51323 1;71700 51293;71723 51262;71753 51240 32;71963 51037 32;71925 50887 33;71873 50745;71775 50640;71633 50512 1;71580 50483;71498 50528;71498 50588 1;71490 50685;71498 50738;71498 50828 1;71498 50903;71430 50963;71363 50948 1;71145 50918;71033 50903;70823 50858 1;70740 50843;70688 50768;70718 50693 1;70755 50580;70725 50512;70748 50393 1;70755 50348;70800 50318;70852 50318 1;70935 50325;70973 50340;71063 50348 1;71145 50363;71190 50250;71168 50168 1;71108 49988;71048 49898;71033 49703 1;70995 49410;71048 49253;71183 48983;70823 48802 50;70440 52448 33;70433 52695;70425 52935;70433 53258 1;70433 53408;70485 53543;70628 53558 1;70740 53573;70808 53617;70928 53588 1;71070 53558;71160 53468;71213 53318 1;71325 52995;71385 52762;71453 52508 32;71475 52380 1;71063 52313;70838 52298;70433 52223;70440 52448 50;69158 60825 1;69428 60720;69713 60660;70088 60675 1;70650 60713;70980 60765;71445 61095 1;71948 61463;72180 61853;72165 62475 1;72150 63105;72270 63443;72570 63990 1;72915 64680;73050 65085;73568 65655 1;74040 66180;74325 66405;74828 66915 1;75180 67283;75450 67492;75968 67492 1;76575 67500;76898 67523;77490 67695 1;78015 67860;78435 67703;78810 68115 1;78990 68325;79117 68385;79365 68490 1;79785 68693;80025 68760;80408 69053 1;80738 69323;80985 69413;81165 69795 1;81375 70283;81637 70643;82170 70650 1;82650 70665;82898 70343;83130 69915 1;83288 69623;83475 69540;83625 69233 1;83768 68925;84038 68790;84390 68813 1;84990 68865;85245 69180;85688 69615 1;86227 70155;86438 70492;87045 70950 1;87600 71385;87810 71865;88508 71933 1;88875 71970;89078 71850;89408 71655 1;89887 71363;89820 70913;90165 70455 1;90525 69983;90750 69765;91245 69413 1;91838 69000;92130 68700;92850 68550 1;93428 68445;93727 68400;94328 68430 1;95145 68483;95535 68670;96368 68693 1;96705 68715;96870 68490;97087 68213 1;97808 67290;97815 66615;98310 65535 1;98558 64973;99060 64815;99690 64815 1;100245 64815;100598 64973;100988 65393 1;101745 66240;102105 66690;102810 67590 1;103200 68115;103440 68363;103988 68715 1;104550 69083;104887 69330;105570 69315 1;105990 69315;106238 69375;106628 69173 1;107137 68925;107355 68693;107887 68453 1;108525 68160;108915 68063;109628 68093 1;110475 68145;110940 68295;111645 68775 1;112395 69300;112860 69443;113565 70035 1;113925 70350;114255 70335;114750 70290 1;115425 70245;115920 70223;116370 69690 1;116790 69195;116850 68790;116925 68130 1;117000 67500;117255 67245;117488 66630 1;117705 66045;117780 65715;117825 65070 1;117840 64883;117855 64793;117870 64590 1;117900 62715;116137 62302;114630 61170 1;113528 60360;112958 59963;111765 59295 1;110460 58575;109860 58125;108608 57293 1;107768 56753;107340 56512;106508 55950 1;105870 55545;105660 55140;104970 54855 1;103785 54375;103260 53992;102090 53490 1;101115 53093;100538 53070;99645 52515 1;98887 52043;98595 51683;97845 51195 1;96975 50640;96600 50153;95588 49950 1;95220 49890;95070 49733;94725 49575 1;93727 49133;93548 48420;92625 47835 1;91995 47445;91620 47325;91088 46815 1;90465 46245;90308 45705;89528 45412 1;89153 45285;88988 45218;88710 45098;69173 58680;69758 58988 1;69930 58950;70020 58927;70200 58875 1;70320 58845;70418 58883;70508 58965;70867 58455 1;70852 58433;70852 58395;70852 58358 1;70838 57983;70838 57795;70808 57420 1;70793 57338;70695 57338;70628 57285 1;70515 57188;70455 57143;70320 57150 1;70193 57165;70163 57105;70065 57113 1;69998 57113;69938 57120;69900 57165 1;69780 57308;69698 57360;69578 57488 1;69383 57698;69262 57885;69165 58073;69173 58680 18;69158 59453 1;69352 59325;69548 59220;69742 59137 1;69893 59078;69848 58568;70200 58523 1;70575 58478;70725 58860;70935 58957 1;71220 59093;71438 59100;71693 59130 1;71850 59153;72068 58860;72300 58905 1;72623 58980;72735 59348;72960 59475 1;73102 59550;73268 59685;73455 59783 1;73913 60052;74055 60285;74018 60802 1;73943 61508;73590 61613;73538 62302 1;73500 62753;73605 62985;73778 63383 1;74010 63953;73875 64380;74295 64823 1;75045 65633;75510 66300;76620 66300 1;77775 66300;78705 66180;79418 67102 1;79748 67545;80168 67463;80580 67823 1;80955 68175;81345 68175;81578 68625 1;81727 68933;81908 69120;82260 69143 1;82568 69165;82650 68865;82815 68580 1;83258 67845;83700 67320;84578 67305 1;85290 67305;85575 67673;86220 67980 1;87165 68460;87660 68895;88740 68903 1;89617 68925;90188 68880;90855 68303 1;91680 67590;92160 66983;93255 66983 1;94065 66983;94477 66945;95295 66983 1;96488 67043;97260 66300;97695 65183 1;98085 64185;98730 63555;99818 63503 1;100770 63473;101318 63735;102060 64343 1;102345 64598;102495 64815;102667 65063;70867 58455;70508 58965 1;70538 58988;70560 59010;70590 59033 1;70733 59198;70935 59115;71130 59010 1;71258 58943;71333 58740;71318 58590 1;71295 58470;71085 58410;70965 58425 1;70920 58440;70875 58492;70867 58455 18;69173 59348;69270 59468 1;69420 59250;69488 59048;69758 58988;69165 58680;69173 59348 18;69150 64508;69158 64500 32;69150 64508 18;69165 61440 1;69240 61403;69233 61290;69233 61185 1;69210 61005;69180 60855;69158 60720;69165 61448;69165 61440 18;69158 59595 1;69195 59558;69233 59520;69270 59468;69165 59340;69165 59603;69158 59595 18;69165 61440 1;69240 61403;69233 61290;69233 61185 1;69210 61005;69180 60855;69158 60720;75105 54075 1;74992 54405;74887 54555;74843 54893 1;74828 54990;74858 55110;74955 55095 1;75075 55088;75300 55110;75390 55050 1;75465 55005;75450 54878;75480 54765 1;75548 54450;75525 54293;75600 53970;75105 54075 18;74813 55433 1;74813 55582;74880 55688;75023 55740 1;75173 55800;75262 55800;75405 55883 1;75540 55980;75645 56033;75683 56190 1;75698 56287;75742 56370;75848 56370 1;75960 56370;75968 56242;76028 56137 1;76080 56033;76133 55988;76230 55898 1;76328 55808;76305 55710;76320 55575 1;76320 55508;76223 55500;76155 55492 1;75645 55455;75398 55373;74895 55410;74813 55433 18;76283 55523 1;76403 55170;76553 55035;76770 54720 1;76770 54510;76440 54728;76253 54810 1;75930 54953;75810 55140;75683 55455;76283 55523 18;77295 53948 1;77100 54218;76995 54345;76845 54630;76733 54765 1;76545 55043;76403 55185;76298 55478;76313 55643 1;76305 55748;76305 55823;76230 55898 1;76133 55988;76080 56033;76028 56137 1;75968 56242;75960 56370;75848 56370 1;75742 56370;75698 56287;75683 56190 1;75645 56033;75540 55980;75405 55883 1;75315 55838;75248 55815;75180 55800;74918 55688 1;74843 55635;74813 55568;74813 55470;74835 54945 1;74835 54930;74835 54915;74843 54893 1;74880 54593;74970 54443;75068 54180 32;76898 54525;76770 54720 33;76620 54938;76508 55065;76410 55238 32;76448 55305 1;76673 55305;76793 55328;77010 55403 1;77070 55433;77130 55463;77183 55410 1;77453 55148;77640 55058;77865 54750 1;77895 54713;77963 54705;77955 54645 1;77865 54278;77588 54188;77273 53985;76898 54525 18;69195 47310 1;69270 47280;69262 47160;69203 47123;69210 47295;69195 47310 18;69203 46635 1;69233 46688;69262 46748;69293 46815 1;69315 46890;69323 46928;69367 46995 1;69405 47070;69450 47115;69533 47100 1;69735 47078;69840 47040;70058 47033;70433 46463;70125 46313;69458 45818;69203 45570;69210 46643;69203 46635 18;69765 44475 1;69818 44130;69840 43943;70005 43620;70020 43530 33;70012 43463;69945 43410;69878 43425 1;69788 43455;69735 43440;69653 43463 1;69570 43493;69585 43568;69540 43628 1;69405 43815;69338 43928;69323 44152 1;69308 44303;69293 44378;69300 44520 32;69323 44595 1;69352 44610;69360 44640;69398 44633;69765 44475 18;69810 44460 1;69908 44415;70005 44385;70140 44310 1;70185 44287;70193 44228;70178 44168 1;70110 43965;70050 43845;70028 43658 32;70020 43530 32;69990 43470 32;69788 44025 32;69735 44483;69810 44460 18;69218 43140;69285 43103;69233 43050 32;69225 43133;69218 43140 18;69203 45593 1;69495 45923;69870 46170;70335 46418 32;70425 46448 1;70500 46305;70553 46230;70635 46080 1;70515 45983;70455 45930;70328 45840 1;70275 45810;70283 45743;70320 45683 1;70358 45630;70373 45600;70418 45540 1;70470 45473;70425 45375;70350 45323 1;70178 45225;70110 45150;69968 45015 1;69818 44888;69788 44753;69780 44550;69765 44475 32;69398 44633 1;69360 44640;69352 44610;69323 44595;69300 44520 33;69293 44378;69308 44303;69323 44152 1;69323 44100;69330 44055;69338 44018 32;69345 43935 1;69293 43957;69248 43980;69210 44003;69210 45600;69203 45593 18;69600 43448;69218 43073;70935 43680 1;70958 43763;71025 43800;71108 43785 1;71183 43777;71220 43710;71227 43628 1;71242 43313;71250 43155;71295 42840 1;71303 42765;71318 42713;71280 42645 1;71198 42525;71123 42495;71018 42398 1;70965 42360;70883 42435;70883 42495 1;70875 42623;70838 42713;70733 42765 1;70620 42825;70545 42818;70455 42893 1;70395 42945;70448 43027;70515 43058 1;70643 43125;70748 43133;70815 43253 1;70890 43410;70860 43515;70943 43673;70935 43680 18;72150 40838;72968 40718;72473 39323;73290 39412;70755 38490 1;70710 38655;70703 38738;70680 38902 1;70665 38985;70710 39060;70793 39068 1;70852 39082;70890 39082;70958 39082 1;71040 39082;71115 39143;71130 39225 1;71137 39360;71115 39435;71123 39563 1;71123 39683;71108 39758;71168 39855 1;71265 40035;71295 40170;71483 40253 1;71558 40290;71640 40283;71640 40193 1;71633 39990;71498 39878;71468 39668 1;71438 39495;71505 39390;71625 39248 1;71678 39180;71760 39188;71850 39203 1;71992 39240;72075 39218;72218 39277 1;72367 39353;72435 39457;72458 39623 1;72495 39945;72495 40110;72473 40425 1;72465 40523;72555 40628;72645 40590 1;72765 40537;72825 40500;72945 40433 1;73020 40395;73065 40350;73080 40260 1;73155 39660;73245 39360;73313 38753;70755 38490 18;71715 42308 1;71708 42338;71715 42368;71745 42368 1;71873 42405;71933 42450;72075 42473 1;72150 42488;72188 42495;72248 42435 1;72398 42293;72428 42203;72623 42105 1;72727 42053;72750 41970;72795 41850 1;72840 41715;72878 41640;72780 41527 1;72713 41468;72645 41453;72563 41468 1;72345 41520;72240 41543;72038 41603 1;71910 41648;71850 41723;71828 41843 1;71783 42030;71753 42128;71715 42308 18;71887 40973 1;71940 40890;71828 40845;71775 40770 1;71655 40628;71648 40440;71625 40253;71588 40260 33;71550 40275;71512 40275;71483 40253 1;71295 40170;71265 40035;71168 39855 1;71108 39758;71123 39683;71123 39563 1;71115 39435;71137 39360;71130 39225 1;71115 39143;71040 39082;70958 39082 1;70890 39082;70852 39082;70793 39068 1;70762 39068;70740 39060;70725 39045 32;70680 39015 1;70538 39240;70477 39360;70380 39593 1;70328 39720;70305 39803;70350 39923 1;70500 40350;70613 40553;70860 40935 1;70905 41010;70980 41018;71063 40995 1;71393 40920;71565 40965;71910 40988;71887 40973 18;71895 40912;72473 40515 32;72473 40425 33;72495 40110;72495 39945;72458 39623 1;72435 39457;72367 39353;72218 39277 1;72075 39218;71992 39240;71850 39203 1;71760 39188;71678 39180;71625 39248 1;71505 39390;71438 39495;71468 39668 1;71498 39878;71633 39990;71640 40193 1;71640 40223;71625 40245;71617 40260 32;71625 40320 33;71648 40485;71663 40650;71775 40770 1;71798 40808;71828 40830;71858 40860;71895 40912 18;74992 41880 1;74835 41978;74738 42037;74663 42195 1;74588 42353;74610 42480;74715 42615 1;74873 42840;75150 42660;75390 42525;74992 41880 18;74693 38873 1;74925 38963;75008 39090;75210 39240 1;75323 39330;75413 39383;75555 39345 1;75653 39330;75660 39180;75600 39098 1;75533 39015;75510 38955;75503 38843;74693 38873 18;75540 40043 1;76695 40020;77280 39975;78443 40088 1;78653 40110;78750 40140;78968 40155 1;79102 40170;79148 40245;79275 40298 1;79665 40478;80438 41018;80820 41213;75578 41010 1;75503 41100;75465 41152;75398 41235 1;75338 41310;75293 41430;75383 41468 1;75450 41513;75480 41543;75563 41565 1;75645 41603;75705 41588;75795 41550 1;76012 41468;76117 41400;76335 41287 1;76425 41243;76500 41265;76590 41310 1;76800 41430;76905 41483;77130 41580 1;77198 41618;77265 41595;77333 41535 1;77490 41393;77558 41310;77730 41168 1;77835 41078;77933 41108;78075 41078 1;78308 41040;78383 40830;78420 40590 1;78443 40433;78435 40350;78450 40178 1;78450 40118;78383 40080;78323 40073 1;78030 40073;77887 40050;77602 40050 1;77355 40050;77227 40027;76988 40035 1;76905 40043;76830 40103;76852 40178 1;76883 40313;76905 40380;76898 40515 1;76883 40658;76867 40800;76740 40815 1;76380 40875;76200 40860;75848 40912 1;75727 40935;75637 40912;75570 40995;75578 41010 18;75653 40433 1;75863 40448;75975 40448;76193 40448 1;76305 40448;76387 40402;76448 40298 1;76523 40162;76575 40095;76650 39945 1;76680 39878;76620 39810;76560 39758 1;76485 39705;76410 39675;76335 39713 1;76095 39832;75975 39893;75720 39945 1;75615 39968;75540 40005;75518 40103 1;75495 40193;75480 40238;75473 40328 1;75458 40402;75548 40440;75623 40433;75653 40433 18;80940 48060 1;81038 47895;81150 47858;81255 47693 1;81398 47468;81383 47295;81390 47018 1;81390 46748;81367 46553;81165 46380 1;80955 46215;80775 46110;80535 46200 1;80265 46313;80168 46448;79980 46658 1;79883 46770;79883 46995;80033 47018 1;80205 47055;80295 47003;80475 46980 1;80588 46973;80745 47063;80700 47168 1;80580 47430;80573 47580;80445 47835;80940 48060 18;78788 49313 1;78975 49117;79125 48998;79133 48720 1;79133 48615;79028 48495;78930 48533 1;78727 48623;78585 48668;78488 48863 1;78405 49012;78323 49103;78383 49253 1;78413 49343;78480 49418;78570 49380 1;78660 49350;78720 49358;78803 49290;78788 49313 18;80835 52140 1;81015 52223;81098 52305;81300 52343 1;81390 52365;81480 52343;81525 52253 1;81585 52117;81555 51975;81435 51885 1;81308 51802;81248 51750;81120 51668;80835 52140 18;82253 53228 1;82463 53310;82680 53265;82740 53108 1;82800 52965;82680 52770;82470 52680 33;82268 52598;82043 52658;81990 52800 1;81923 52950;82050 53145;82253 53228 18;84458 54353 1;84608 54420;84690 54427;84855 54473 1;84975 54518;85035 54548;85163 54585 1;85598 54720;85838 54735;86295 54795 1;86318 54802;86363 54818;86363 54787 1;86288 54495;86145 54383;86055 54082 1;86033 54023;85935 54068;85890 54105 1;85748 54225;85673 54285;85515 54375 1;85440 54420;85387 54435;85313 54412 1;85110 54367;84990 54383;84810 54285 1;84645 54203;84653 54037;84488 53970 1;84293 53903;84173 54045;84023 54173;84458 54353 18;88260 54473 1;88575 54367;88703 54248;89003 54090 1;89033 54075;89070 54015;89040 54008 1;88905 54000;88838 53970;88718 54008 1;88658 54030;88590 54090;88568 54030 1;88523 53955;88515 53910;88485 53820 1;88440 53730;88305 53783;88238 53850 1;87998 54098;87983 54308;87870 54623;88260 54473 18;82643 48832 1;82425 49073;82178 49140;82148 49455 1;82117 49688;82117 49875;81915 49973 1;81810 50025;81727 49965;81645 50033 1;81615 50055;81608 50070;81600 50100 1;81548 50250;81518 50325;81503 50475 1;81488 50543;81398 50715;81458 50745 1;81578 50820;81698 50768;81848 50783 1;82178 50828;82328 50865;82635 51015 1;82793 51105;82958 51300;83115 51398 1;83168 51443;83280 51210;83325 51150 1;83393 51068;83460 50970;83565 51008 1;83760 51082;83865 51143;83992 51308 1;84105 51465;84195 51525;84367 51608 1;84615 51742;84773 51742;85058 51795 1;85553 51893;85793 51945;86295 52035 1;87083 52193;87473 52320;88238 52568 1;88448 52643;88620 52755;88628 52973 1;88628 53078;88613 53175;88710 53213 1;88852 53287;88943 53213;89108 53205 1;89280 53205;89385 53078;89550 53145 1;89738 53235;89850 53258;90008 53393;90510 53123;91395 52680;90578 51810;90270 51563;89798 51210;89258 51000;88860 50820;87750 50250;87435 50100;86700 49778;86363 49710;85920 49665;84825 49305;84352 49177;83617 48998;82643 48832 18;88860 52350 1;88635 52238;88583 52005;88650 51758 1;88680 51637;88823 51637;88950 51660 1;89265 51728;89393 51870;89633 52088 1;89745 52200;89738 52365;89640 52478 1;89453 52703;89160 52552;88920 52395;88860 52350 18;88920 52395 1;89160 52552;89453 52703;89640 52478 1;89738 52365;89745 52200;89633 52088 1;89393 51870;89265 51728;88950 51660 1;88823 51637;88680 51637;88650 51758 1;88583 52005;88635 52238;88920 52395 18;81293 54188 1;81143 53963;81045 53820;80798 53723 1;80693 53685;80580 53700;80535 53798 1;80468 53925;80445 54068;80565 54150 1;80783 54323;80910 54383;81150 54525 1;81210 54570;81338 54578;81338 54495 1;81338 54345;81367 54225;81255 54128;81293 54188 18;81203 54713;82095 54735;81180 56423 33;81218 56378;81270 56332;81323 56280 32;81390 56205 1;81173 55950;81083 55718;80918 55425 1;80880 55380;80805 55410;80753 55425 1;80633 55470;80565 55552;80617 55658 1;80753 55988;80918 56175;81135 56453;81180 56423 50;81367 56242 1;81083 56505;80940 56730;80783 57075 1;80723 57203;80948 57203;81083 57188 1;81413 57165;81563 57023;81840 56835;81367 56242 18;81608 57008 1;81795 57255;81915 57412;81938 57713 1;81945 57915;81908 58058;82073 58162 1;82268 58305;82380 58365;82620 58418 1;82943 58500;83130 58470;83430 58628 1;83512 58680;83588 58770;83535 58845 1;83453 58950;83430 59018;83325 59078 1;83288 59108;83333 59160;83378 59175 1;83453 59213;83490 59258;83580 59273 1;83925 59340;83933 58883;84150 58590 1;84165 58568;84098 58590;84083 58568 1;83955 58463;83887 58410;83753 58320 1;82935 57818;82553 57503;81863 56835;81795 56865 33;81735 56910;81683 56948;81630 56985 32;81608 57008 18;79560 57285;80573 57308 1;80303 57600;80115 57885;80160 58275;107977 61328;109290 59745 32;109778 56753 32;111743 56580 32;111345 53918 32;113438 53565 32;115530 48675 32;118710 48150;118643 47520 32;119880 47445;121268 47355 32;95288 77985;95070 77535;94470 77835 32;94538 77985;95288 77985 18;96922 77460;96352 75968 32;95693 76223 32;95565 75900 32;94553 76298 32;94890 77175 32;95798 76830 32;96150 77760 32;96922 77460 18;102600 78008;102600 77453 32;101512 77453;101512 78008;102600 78008 18;103118 76590;102930 77602 32;104265 77835 32;104453 76830 32;103118 76590 18;124433 72585;122693 69503 32;122078 69855 32;121935 69608 32;121073 70102 32;123158 73793 32;122880 73958 32;123480 75023 32;124433 74490;124440 72585;124433 72585 18;124440 69053;124297 69143 32;124208 69000 32;123833 69240 32;124448 70208;124448 69053;124440 69053 18;124455 65903;124005 66300 32;124455 66818;124462 65903;124455 65903 18;119250 65843;119258 66113 32;118950 66120 32;119003 67515 32;119573 67485 32;119550 66637 32;120488 66600 32;120488 66405 32;120870 66390 32;120900 66983 32;121590 66953 32;121575 66173 32;121080 66188 32;121058 65235 32;120383 65250 32;120405 65805 32;119250 65843 18;114968 65355;116408 65280 32;116430 65843 32;117210 65813 32;117158 64995 32;116768 65025 32;116700 63945 32;116070 63990 32;116070 64155 32;115665 64177 32;115680 64537 32;114698 64598 32;114705 64883 32;114330 64912 32;114413 66608 32;115028 66578 32;114968 65355 18;113137 65588;113085 66248 32;113542 66278 32;113565 66030 32;113783 66038 32;113820 65640 32;113137 65588 18;114848 69855;115837 69293 32;116325 69668 32;116250 70065 32;116933 70215 32;117075 69593 32;116933 69555 32;117120 68685 32;116483 68565 32;116430 68887 32;115462 68625 32;115283 68213 32;114518 68670 32;114683 69053 32;114518 69150;114848 69855 18;124493 54315;123960 54375 32;123983 54495 32;123120 54600;123255 55733 32;124140 55620 32;124118 55350 32;124493 55305;124500 54315;124493 54315 18;120195 53985;120712 58133 32;121178 58088;120660 58148;121012 58110;120945 57510 32;120578 57540;120885 54488;120945 54945 32;121080 54915 32;121193 55680 32;121672 55605 32;121628 55223 32;121905 55170 32;121935 55373 32;122520 55283 32;122408 54398 32;121635 54503 32;121628 54383 32;120885 54488 18;119970 55710;118658 55875 32;118635 55710 32;118012 55785 32;118102 56528 32;118268 56512 32;118403 57585 32;119400 57457 32;119265 56408 32;120038 56310 32;119970 55710 18;119917 59033;119955 59430 32;119265 59505 32;119363 60315 32;120090 60225 32;120060 59850 32;120998 59738 32;120915 58920 32;119917 59033 18;116977 59768;118170 59558 32;118028 58770 32;117533 58867 32;117488 58658 32;116422 58853 32;116535 59535 32;115973 59640 32;116093 60375 32;117053 60218 32;116977 59768 18;117195 62955;117068 63120 32;117368 63353;117727 62895;118268 62805;118073 61515 32;118425 61470 32;118335 60893 32;118028 60945 32;117968 60570 32;117233 60690 32;117292 61088 32;117180 61117 32;117233 61448 32;116977 61492 32;117195 62955 18;122400 63923;123428 63795 32;123300 62760 32;124313 62617 32;124208 61800 32;122760 61980 32;122813 62408 32;122212 62475 32;122400 63923 18;124470 59617;122917 59820;123075 61088 32;123938 60968 32;123893 60518 32;124477 60443;124477 59617;124470 59617 18;121568 59512;124485 59160;124485 56677;121178 57105;69135 68858 1;71648 70628;73065 71580;75713 73440 1;77543 74738;78413 75458;80175 76845 1;80723 77288;81060 77535;81510 77940;82133 77948;82193 77685;79598 75593;74040 71685;69135 68370;69135 68873;69135 68858 18;82410 77948;82260 77685 32;82140 77948;82410 77948 18;81503 77933 1;81060 77535;80723 77288;80175 76845 1;78413 75458;77543 74738;75713 73440 1;73058 71580;71648 70628;69128 68850;69128 72615;69352 74865;73883 77925;81503 77940;81503 77933 18;120083 39735;120938 39900 32;121118 38902 32;120270 38738 32;120083 39735 18;119220 43928;115898 44108 32;112658 44033 32;109500 43140 32;109493 41123 32;109485 39743 32;109485 38348 32;110948 38340 32;114120 38318 32;114450 40470 32;115852 41730 32;115852 42428;116325 42428;116325 41738;118500 40335 32;118605 37103 32;122085 38655 32;124553 37553;110438 64005;111825 64005 32;111825 64073 32;112635 64073 32;112635 63435 32;112080 63435 32;112080 63052 32;111120 63052 32;111120 63255 32;110438 63255 32;110438 64005 18;110385 60015;110415 60323 32;110078 60360 32;110137 60795 32;109733 60840 32;109808 61358 32;110422 61275 32;110385 60908 32;110685 60870 32;110715 61103 32;111623 60990 32;111495 59880 32;110385 60015 18;112837 61170;113550 61088 32;113550 61103 32;113535 60953 32;113790 60915 32;113828 61238 32;114458 61162 32;114375 60495 32;114098 60525 32;113993 59655 32;113430 59715 32;113453 59925 32;112703 60008 32;112837 61170 18;111300 59115;112208 59010 32;112005 57270 32;111098 57367 32;111300 59115 18;113648 58455;114465 58365 32;114428 58050 32;114810 57998 32;114735 57345 32;114563 57353 32;114488 56662 32;113453 56775 32;113648 58455 18;114930 58658;113153 58867 32;113190 59213 32;114915 59018 32;114615 56235;114398 54188 32;113010 54345 32;113070 54930 32;113618 54885 32;113768 56325 32;114615 56235 18;115845 55103;115928 55740 32;116573 55643 32;116498 55012 32;115845 55103 18;115792 53550;115860 54533 32;116775 54465 32;116805 54735 32;117360 54690 32;117278 53445 32;115792 53550 18;119738 51653;118508 51735 32;118523 51975 32;117983 52012 32;118050 53025 32;118890 52965 32;118875 52710 32;119797 52643 32;119738 51653 18;115628 50670;115785 51968 32;115387 52020 32;115433 52455 32;116520 52328 32;116475 52028 32;117128 51953 32;116940 50512 32;115628 50670 18;116258 50453;116955 50558 32;117053 49905 32;116355 49793 32;116258 50453 18;117265 49184;117337 50190 32;118448 50100 32;118383 49101 32;117265 49184 18;119663 51090;120413 51398 32;120345 50783 32;119850 50588 32;119663 51090 18;121275 52890;121538 52912 32;121590 52425 32;121313 52387 32;121275 52890 18;119595 49245;120863 49245 32;120863 48698 32;120443 48698 32;120443 48510 32;120593 48510 32;120593 47955 32;119310 47955 32;119310 48488 32;119715 48488 32;119715 48735 32;119595 48735 32;119595 49245 18;121748 50153;121770 51173 32;123060 51128 32;123038 50115 32;121748 50153 18;124508 50063;124050 50010;123938 51045 32;124508 51105;124515 50063;124508 50063 18;124515 46845;123540 46823;123518 47738 32;124523 47760;124523 46845;124515 46845 18;124523 46245 1;123135 46343;122685 46275;121245 46313;121272 47476;91035 50423;81653 48435;82755 46448 1;82883 45675;82545 45270;82598 44475;81203 60323;82369 75957;83640 59115 1;83333 59078;83175 59213;82883 59137 1;82545 59063;82380 59010;82050 58957 1;81495 58875;81173 58658;80910 58170 1;80790 57960;80715 57863;80633 57637 1;80565 57473;80408 57398;80227 57420 1;79852 57473;79643 57480;79313 57653 1;79155 57742;79035 57998;79193 58080 1;79620 58328;79808 58508;80273 58695 1;80655 58860;80895 58988;81090 59355 1;81240 59662;81383 59798;81690 59948 1;82163 60188;82380 60345;82860 60563;83640 59115 18;87345 62145 1;87405 61965;87503 61912;87645 61770 1;88020 61395;88283 61260;88545 60795 1;88568 60758;88560 60698;88515 60683 1;87675 60533;87248 60443;86483 60068 1;86280 59978;86168 59948;85988 59828;85800 59760 33;85688 59963;85620 60105;85523 60330 1;85418 60555;85223 60593;84983 60615 1;84840 60630;84720 60630;84608 60623 32;84398 60525 1;84173 60660;84098 60758;83850 60825 1;83543 60915;83378 60893;83063 60870 1;82973 60870;82875 60840;82852 60930 1;82845 61012;82755 61058;82808 61103 1;83010 61328;83040 61470;83115 61762 1;83183 62093;83198 62273;83115 62588 1;83085 62700;83295 62783;83378 62700 1;83625 62453;83715 62242;84053 62115 1;84615 61912;85050 62490;85215 63068 1;85260 63240;85328 63323;85477 63420 1;85905 63713;85973 64035;86183 64508 1;86205 64567;86288 64628;86325 64575 1;86460 64373;86520 64268;86625 64035 1;86655 63960;86700 63893;86655 63818 1;86588 63728;86505 63728;86415 63668 1;86250 63578;86160 63443;86190 63248 1;86213 63090;86303 63037;86393 62895 1;86483 62753;86430 62617;86340 62468 1;85943 61875;85928 61440;85965 60720 1;85965 60570;86325 60713;86318 60863 1;86265 61650;86528 62137;87120 62655;87345 62145 18;80123 63098 33;80018 63158;79913 63330;79800 63390 1;79170 63728;79058 64073;78705 64635 32;78510 64770 33;78735 64973;78983 65183;79313 65415 1;79538 65595;79740 65745;79935 65873 32;80250 65970 1;80768 65678;81098 65528;81383 64995 1;81420 64912;81323 64823;81233 64808 1;80783 64770;80550 64733;80123 64598 1;80055 64582;80055 64463;80123 64425 1;80408 64283;80528 64170;80820 64028 1;80933 63975;80985 63900;81015 63773 1;81038 63660;81038 63600;81060 63480 1;81068 63375;81083 63300;81030 63203 1;80985 63143;80918 63143;80843 63158 1;80708 63188;80655 63233;80535 63270 1;80408 63323;80325 63203;80250 63090;80123 63098 50;82163 66180 1;82530 66173;82725 66165;83085 66053 1;83205 66015;83235 65910;83258 65775 1;83310 65438;83325 65220;83565 64957 1;83693 64815;83700 64695;83843 64552 1;83910 64485;83918 64410;83887 64313 1;83843 64200;83798 64148;83775 64028 1;83753 63953;83640 63968;83580 64012 1;83378 64155;83213 64185;82988 64102 1;82883 64073;82830 64155;82755 64223 1;82455 64485;82193 64628;81810 64523 1;81720 64500;81623 64530;81608 64613 1;81548 64845;81488 64980;81555 65205 1;81660 65573;81788 65730;81960 66068 1;81990 66143;82035 66188;82117 66180;82163 66180 18;84135 65730 1;84600 65835;84915 65948;85335 65708 1;85403 65670;85403 65535;85328 65498 1;84908 65340;84780 65040;84645 64613 1;84608 64500;84465 64387;84383 64470 1;84068 64770;83933 65025;83940 65453 1;83940 65573;83940 65715;84060 65723;84135 65730 18;74843 63832 1;74850 64035;74948 64200;75060 64192 1;75165 64192;75262 64012;75248 63810 33;75248 63615;75143 63450;75038 63457 1;74925 63457;74835 63637;74843 63832 18;79140 65190 1;78855 64965;78773 64733;78428 64635 1;78180 64575;78068 64492;77865 64343 1;77490 64080;77543 63675;77145 63457 1;76958 63367;76830 63578;76703 63735 1;76635 63818;76658 63915;76718 63998 1;76808 64148;76898 64207;76958 64373 1;76980 64448;77003 64500;76958 64552 1;76898 64620;76890 64665;76883 64740 1;76860 64845;76980 64860;77063 64920 1;77475 65273;77633 65520;78075 65835 1;78218 65948;78330 65955;78518 65948 1;78900 65940;79080 65783;79418 65580;79140 65190 18;79913 65992 1;79598 66165;79433 66255;79178 66495 1;79080 66585;79020 66727;79117 66818 1;79500 67193;79725 67335;80130 67680 1;80205 67755;80318 67852;80385 67762 1;80708 67313;80685 66960;81068 66548;79913 65992 18;76050 66030 1;76485 65633;76815 65393;76905 64785 1;76913 64710;76867 64635;76793 64582 1;76725 64552;76628 64537;76560 64560 1;76403 64643;76448 64800;76395 64950 1;76313 65145;76283 65250;76148 65385 1;75998 65535;76058 65700;75945 65858 1;75923 65895;75915 65933;75915 65963 1;75930 66038;75960 66075;76012 66038;76050 66030 18;69143 67950;72930 70605 1;74602 70965;73965 69128;74866 68433 1;74939 68377;74625 67815;74535 67793 1;74198 67733;74018 67725;73688 67770 1;73508 67800;73425 67883;73253 67883 1;73050 67883;72960 67845;72765 67838 1;72713 67838;72675 67793;72690 67740 1;72727 67500;72750 67373;72758 67125 1;72758 67005;72668 66960;72578 66878 1;72390 66735;72315 66645;72150 66473 1;72060 66390;72075 66308;72075 66188 1;72075 65865;72090 65648;71887 65385 1;71843 65332;71760 65370;71723 65423 1;71543 65693;71602 65895;71573 66210 1;71558 66330;71543 66398;71468 66473 1;71190 66735;70980 66825;70613 66848 1;70538 66855;70455 66833;70440 66900 1;70358 67155;70290 67290;70117 67485 1;70005 67613;69810 67755;69653 67710 1;69420 67665;69293 67710;69135 67635;69143 67943;69143 67950 18;70658 67200 1;70815 67073;70988 67012;71040 67073 1;71093 67125;71003 67290;70852 67425 33;70695 67560;70500 67635;70455 67583 1;70403 67515;70477 67320;70635 67178;70658 67200 18;72083 69983 1;72240 69840;72383 69773;72413 69555 1;72435 69360;72315 69210;72128 69150 1;71715 69030;71498 69015;71085 68918 1;70943 68887;70852 68798;70852 68655 1;70852 68512;71010 68468;71160 68468 1;71573 68483;71783 68588;72158 68768 1;72420 68903;72637 68933;72893 68775 1;73073 68663;73223 68633;73433 68700 1;73800 68828;73920 69036;73965 69426 1;74002 69786;73782 69624;73602 69924 1;73422 70224;73292 70023;72908 70230 1;72763 70308;72615 70193;72503 70313;72083 69983 18;79673 75315 1;79718 75120;79748 74992;79658 74805 1;79613 74723;79635 74663;79673 74565 1;79718 74430;79680 74295;79560 74220 1;79403 74130;79283 74175;79110 74205 1;78998 74227;78923 74213;78833 74145 1;78000 73590;77550 73358;76748 72765 1;76665 72713;76605 72765;76515 72765 1;76425 72773;76380 72788;76298 72818;79673 75315 1;79718 75120;79748 74992;79658 74805 1;79613 74723;79635 74663;79673 74565 1;79718 74430;79680 74295;79560 74220 1;79403 74130;79283 74175;79110 74205 1;78998 74227;78923 74213;78833 74145 1;78000 73590;77550 73358;76748 72765 1;76665 72713;76605 72765;76515 72765 1;76425 72773;76313 72818;76230 72848;79673 75315 18;75428 72300 1;75248 71813;74963 71655;74550 71340 1;74453 71273;74363 71333;74265 71385;75428 72300 1;75248 71813;74963 71655;74550 71340 1;74453 71273;74280 71378;74183 71430;75428 72300 18;82815 77798 1;82838 77633;82785 77512;82658 77400 1;82253 77070;82073 76867;81630 76598 1;81383 76455;81405 76193;81473 75915 1;81495 75818;81525 75720;81443 75660 1;81090 75428;80903 75308;80505 75188 1;80363 75150;80265 75120;80153 75203 1;80025 75293;79988 75367;79898 75480;82815 77798 18;79898 75480 1;79988 75367;80025 75293;80153 75203 1;80265 75120;80363 75150;80505 75188 1;80903 75308;81090 75428;81443 75660 1;81525 75720;81495 75818;81473 75915 1;81405 76193;81383 76455;81630 76598 1;82073 76867;82253 77070;82658 77400 1;82785 77512;82838 77633;82815 77798;86280 77955;86595 76823;88125 77093;89985 76545 32;90015 73095 32;88875 72420;87465 72203 32;89168 68550;90420 66930 32;92348 65805 32;97688 64012 32;98828 66390;98977 70193 32;99893 75285;83078 77940 1;83040 77468;83003 77137;83078 76590 1;83137 76095;83168 75840;83220 75338;86512 76725 1;86415 76695;86325 76680;86265 76748 1;86108 76920;86108 77055;85965 77227 1;85905 77295;85973 77400;86055 77415 1;86168 77445;86227 77475;86348 77505;86512 76725 18;87398 76463 1;87690 76448;87593 76117;87480 76095 1;87173 76058;86970 76080;86670 76043 1;86610 76043;86535 76050;86535 76110 1;86528 76245;86565 76313;86580 76440 1;86588 76553;86723 76545;86835 76538 1;87060 76530;87173 76500;87405 76463;87398 76463 18;87788 76178 1;87788 76298;87870 76395;87990 76395 1;88313 76395;88560 76515;88800 76283 1;88920 76163;88875 75908;88710 75855 1;88508 75803;88380 75848;88208 75953 1;88073 76035;87983 76028;87855 76095;87788 76178 18;87068 75180 1;86955 75023;86948 74895;86805 74768 1;86760 74745;86715 74753;86678 74768 1;86640 74798;86610 74835;86602 74865 1;86580 74925;86543 74985;86528 75038 1;86505 75113;86512 75173;86595 75195 1;86760 75285;86843 75352;87038 75352 1;87068 75352;87083 75330;87083 75285 1;87090 75255;87075 75218;87068 75180 18;87293 75030 1;87488 74850;87578 75458;87803 75293 1;87893 75233;87975 74400;87900 74318 1;87713 74123;87698 73973;87548 73755 1;87503 73703;87435 73605;87398 73658 1;87248 73845;87180 73943;87045 74137 1;86955 74265;86835 74348;86887 74490 1;86977 74745;87090 74843;87240 75068;87293 75030 18;88223 75090 1;88898 75262;89250 75323;89903 75570 1;90023 75623;90030 75315;89925 75240 1;89685 75083;89558 74992;89415 74745 1;89363 74663;89273 74655;89183 74678 1;88838 74790;88590 74685;88238 74648 1;88185 74648;88223 74715;88223 74760;88223 75090 18;87218 75090 1;87345 75300;87443 75443;87690 75473 1;87878 75503;88043 75480;88140 75293 1;88283 75023;88313 74887;88230 74633 1;88178 74490;88058 74333;87923 74393;87218 75090 18;88695 69360 1;88463 69278;88343 69240;88110 69173 1;88028 69158;87930 69113;87908 69188 1;87848 69352;87855 69450;87855 69615 1;87848 69953;87945 70178;88223 70358;88695 69360 18;86227 66795 1;86423 66795;86520 66855;86715 66818 1;86880 66788;86775 66570;86790 66390 1;86790 66315;87024 66274;87069 66192 1;87174 66004;86948 65918;86820 65813 1;86685 65708;86453 65708;86393 65865 1;86258 66195;86120 66278;86083 66624;86227 66795 18;89145 60818 1;89070 61177;88973 61328;88980 61688 1;88980 61778;89018 61778;89100 61808 1;89273 61898;89400 61867;89595 61800 1;90135 61628;90518 61523;91020 61800 1;91170 61890;91275 61875;91448 61860 1;91613 61853;91695 61838;91867 61830 1;91928 61830;91973 61800;92010 61740 1;92145 61530;92258 61433;92340 61185 1;92370 61088;92393 60998;92505 60975 1;93053 60893;93315 60742;93878 60742 1;93960 60742;94050 60735;94065 60645 1;94073 60593;94080 60563;94102 60503;91965 60390 1;92108 60533;92198 60623;92430 60630 1;92610 60637;92753 60518;92850 60345;91965 60390 18;92288 60113 1;92175 59948;92078 59835;91883 59820 1;91583 59805;91433 59753;91140 59783 1;90975 59805;90930 60023;90953 60180;92288 60113 18;95493 60343 1;95415 60757;95610 61119;95880 61082 1;96120 61052;96212 60605;96242 60357;95493 60343 18;95475 60542 1;95505 60812;95610 61119;95880 61082 1;96120 61052;96158 60804;96188 60556;87000 60270 1;87030 61200;86760 61733;87120 62580 1;87255 62910;87593 62873;87953 62895 1;88523 62940;88965 62760;89363 63173 1;89783 63623;90098 63938;90713 63908 1;91117 63893;91305 63750;91695 63600 1;91852 63540;91867 63383;91867 63203 1;91852 62948;91867 62685;92108 62580 1;92400 62460;92595 62625;92850 62423 1;93068 62250;93165 62153;93330 61920 1;93525 61650;93645 61478;93968 61380 1;94433 61245;94583 60878;94703 60398 1;94755 60180;94260 60188;94140 60367;94102 60503 33;94080 60563;94073 60593;94065 60645 1;94050 60735;93960 60742;93878 60742 1;93315 60742;93053 60893;92505 60975 1;92393 60998;92370 61088;92340 61185 1;92258 61433;92145 61530;92010 61740 1;91973 61800;91928 61830;91867 61830 1;91695 61838;91613 61853;91448 61860 1;91275 61875;91170 61890;91020 61800 1;90518 61523;90135 61628;89595 61800 1;89400 61867;89273 61898;89100 61808 1;89018 61778;88980 61778;88980 61688 1;88973 61328;89070 61177;89145 60818 32;89078 60720 1;88313 60675;87915 60615;87210 60323;87000 60270 18;88223 61200 33;87923 61508;87675 61965;87420 62438 1;87315 62625;87180 62693;87128 62850 32;87210 62970 1;87398 63075;87518 63090;87705 63203 1;87810 63278;87885 63353;87878 63480 1;87848 63698;87818 63795;87765 63998 1;87720 64133;87915 64177;88058 64170 1;88238 64162;88335 64035;88380 63855 1;88477 63427;88530 63218;88590 62775 1;88620 62505;88673 62340;88560 62085 1;88410 61778;88410 61448;88395 61103;88223 61200 50;91140 64050 1;91170 63998;91140 63953;91140 63885;91140 63832 33;91012 63878;90878 63908;90713 63908 1;90098 63938;89783 63623;89363 63173 32;89265 63075 1;89213 62648;89295 62430;89333 61995;89318 61867 33;89250 61867;89175 61853;89100 61808 1;89018 61778;88980 61778;88980 61688 1;88973 61328;89070 61177;89145 60818 32;88875 60713 1;88740 60690;88620 60585;88545 60690 1;88470 60787;88485 60870;88440 60975;88395 61103 33;88410 61448;88410 61778;88560 62085 1;88673 62340;88620 62505;88590 62775 1;88575 62865;88560 62940;88553 63015 32;88538 63082 33;88492 63345;88448 63540;88380 63855 1;88335 64035;88238 64162;88058 64170 1;87968 64177;87863 64162;87803 64125 32;87742 64102 1;87668 64268;87660 64365;87683 64537 1;87698 64695;87765 64815;87923 64852 1;88163 64920;88290 64942;88545 64950 1;88770 64965;88725 65302;88958 65355 1;89130 65400;89235 65265;89415 65302 1;89790 65393;90000 65453;90383 65370 1;90510 65348;90585 65302;90660 65190 1;90908 64800;90938 64552;91117 64117;91140 64050 18;87548 67688 1;88477 66870;88988 66405;90188 66060;91898 62258 1;92018 62220;91950 62025;91860 61927;91762 61838 33;91650 61845;91575 61860;91448 61860 1;91275 61875;91170 61890;91020 61800 1;90518 61523;90135 61628;89595 61800 1;89498 61838;89423 61860;89348 61867 32;89310 62183 1;89303 62228;89325 62258;89370 62258 1;89753 62258;89940 62220;90330 62190 1;90983 62145;91313 62302;91980 62273;91898 62258 18;107783 61703;106455 61305;105885 62887 32;106530 63255;107783 61703 18;106583 63278;105885 62887 32;106455 61305;99023 52508 1;98977 52830;98948 52988;98910 53302 1;98895 53378;98955 53445;99030 53445 1;99645 53475;99960 53408;100583 53325 1;100658 53318;100762 53355;100748 53423 1;100583 54023;100508 54315;100387 54915 1;100365 55012;100410 55140;100508 55125 1;100665 55103;100740 55058;100898 54998 1;101070 54938;101085 54780;101167 54608 1;101400 54098;101505 53828;101625 53265 1;101670 53033;101580 52898;101475 52673;99023 52508 18;98273 54457 1;98378 54660;98445 54780;98430 54998 1;98422 55058;98468 55088;98528 55095 1;98843 55185;98977 55328;99218 55552 1;99248 55590;99308 55530;99315 55478 1;99330 55223;99360 55095;99398 54832 1;99405 54773;99390 54540;99330 54533 1;99172 54525;99113 54653;98977 54578 1;98753 54465;98625 54465;98385 54465;98273 54457 18;99262 55545 1;99712 55635;99968 55785;100417 55658 1;100515 55635;100583 55575;100613 55470 1;100658 55298;100733 55223;100748 55035 1;100748 54885;100538 55080;100395 55035 1;100065 54953;99765 54585;99518 54443 1;99420 54390;99405 54503;99315 54555;99262 55545 18;98565 54585 1;98738 54105;98813 53873;98895 53385 1;98813 53378;98723 53370;98625 53370 1;98393 53370;98273 53355;98063 53423 1;97755 53520;97643 53738;97545 54037 1;97508 54143;97493 54195;97462 54300 1;97440 54360;97448 54435;97508 54435;97538 54435 1;97868 54443;97958 54548;98295 54555 1;98393 54563;98468 54578;98565 54585 18;99615 53423;99540 54465 32;99600 54503 33;99810 54660;100065 54945;100350 55028 32;100387 54915 33;100508 54315;100583 54023;100748 53423 1;100762 53355;100658 53318;100583 53325 1;100215 53378;99953 53423;99683 53445;99615 53423 18;98977 52650;98977 52808 1;98955 52965;98933 53108;98910 53302;98835 53378 1;98775 53378;98700 53370;98625 53370 1;98393 53370;98273 53355;98063 53423 1;97755 53520;97643 53738;97545 54037 1;97508 54143;97493 54195;97462 54300 1;97440 54360;97448 54435;97508 54435;97538 54435 1;97868 54443;97958 54548;98295 54555;98415 54570 1;98475 54578;98528 54585;98602 54585 1;98880 54608;99008 54690;99233 54623 1;99360 54585;99413 54548;99540 54480 1;99600 54450;99608 54420;99615 54345 1;99630 53978;99660 53933;99667 53558 1;99667 53498;99667 53415;99608 53415 32;99743 53445 1;99990 53423;100238 53378;100583 53325 1;100613 53325;100650 53332;100680 53340 33;100725 53363;100755 53385;100748 53423 1;100718 53512;100695 53595;100672 53677;100628 53865 1;100538 54210;100470 54480;100387 54915 1;100365 55012;100410 55140;100508 55125 1;100665 55103;100740 55058;100898 54998 1;101070 54938;101085 54780;101167 54608 1;101400 54098;101505 53828;101625 53265 1;101655 53093;101610 52973;101542 52823 32;93480 52238;93908 53168 32;94965 53228 32;95242 52927 32;94725 52155;93480 52238 18;98415 53355 1;98258 53205;98198 53063;97988 53003 1;97913 52988;97905 52867;97965 52815 1;98085 52710;98160 52635;98183 52470;98047 52305 33;97830 52283;97523 52358;97283 52328 1;95175 52125;94463 51915;92595 52455 32;92325 52530 33;91867 52695;91523 52853;91163 53018 32;91170 53078 33;91215 53175;91238 53250;91298 53355 1;91320 53423;91365 53453;91440 53453 1;91583 53453;91658 53438;91808 53438 1;91883 53438;91935 53505;91943 53580 1;91943 53662;91950 53723;91958 53783 32;91845 53820 1;91455 54098;91433 54443;91373 54908 1;91335 55170;91313 55177;91373 55433 1;91403 55613;91815 55740;91852 55860 1;91928 56093;91823 56438;91770 56753 1;91703 57060;91695 57375;91710 57623 1;91755 58245;91958 58725;92198 59460;92273 59512 32;92992 59168 32;93090 59340 32;93210 59393 1;93600 59655;93773 59820;94193 60037 1;94335 60120;94575 60255;94613 60082;94650 60023 33;94665 59798;94650 59490;94867 59490 32;95063 59378 33;95333 59355;95475 59325;95835 59235 1;96413 59108;96750 58845;96968 58313 1;97215 57698;97268 57345;97297 56677 32;97283 56535 33;97283 56378;97238 56302;97260 56137 1;97260 56078;97275 56018;97290 55965 32;97283 55740 1;97297 55440;97313 55283;97320 54975;97320 54818 33;97335 54668;97380 54578;97425 54412 32;97462 54300 33;97493 54195;97508 54143;97545 54037 1;97643 53738;97755 53520;98063 53423 1;98160 53393;98235 53378;98318 53378 32;98415 53355 18;95310 60120;97208 60075 32;97215 59963 33;97268 59550;97283 59302;97403 58845 1;97545 58275;97740 57938;97770 57345 1;97778 57105;97792 57098;97613 56933 1;97485 56828;97350 56775;97297 56655 32;97290 56738 33;97260 57367;97208 57720;96968 58313 1;96750 58845;96413 59070;95835 59198 1;95393 59310;95273 59355;94830 59400 32;94867 59490 32;94988 59520 33;95137 59595;95205 59805;95265 60008;95310 60120 18;98573 52365 1;99278 52440;99938 52515;100815 52590 1;102773 52515;103672 52568;105645 52350 1;106800 52223;107385 51990;108405 51420 1;109658 50723;109965 50213;111165 49410 1;112042 48818;112868 48608;113925 48473 1;114683 48383;115185 48173;115815 47730 1;116408 47318;116760 46883;117308 46620 1;117727 46425;117983 46162;118185 45990;89753 53745 1;89895 53805;89963 53865;90128 53873 1;90262 53887;90398 53940;90473 53820 1;90548 53693;90443 53580;90360 53445;89753 53745 18;89963 57480;84833 56933 1;84810 57060;84855 57188;84983 57218 1;85380 57330;85620 57353;85943 57608 1;86153 57780;86288 57818;86512 57975 1;86588 58035;86678 57938;86708 57840 1;86805 57480;86790 57278;86813 56895 1;86820 56707;86828 56610;86798 56423 1;86768 56295;86670 56198;86543 56213 1;85898 56295;85605 56483;85005 56723 1;84893 56768;84833 56783;84810 56895;84833 56933 18;84818 58733;84930 58762 33;84960 58320;84870 58028;85140 57668 1;85238 57540;85283 57473;85380 57338 32;84810 57052 33;84593 57308;84548 57480;84323 57713 1;84262 57773;84195 57855;84135 57795 1;83933 57630;83775 57623;83580 57450 1;83528 57412;83453 57383;83415 57435 1;83370 57495;83340 57525;83310 57563 32;83280 57623 32;84053 58148;84818 58733 18;85890 59340 1;85943 59025;85973 58823;86198 58560 1;86355 58380;86438 58260;86558 58065 32;86550 57998 33;86288 57818;86153 57780;85943 57608 1;85755 57465;85590 57398;85418 57338 32;85380 57338 33;85283 57473;85238 57540;85140 57668 1;84878 58020;84953 58298;84930 58718 32;84923 58808 32;85875 59423;85890 59340 18;87878 54787;86820 55020 32;86378 55005 32;84975 54742 32;84533 54585 32;84053 54405 32;84023 54495 33;83745 55440;83910 56250;84780 56828 32;84900 56768 33;84930 56753;84960 56745;85005 56723 1;85605 56483;85898 56295;86543 56213 1;86670 56198;86768 56295;86798 56423 1;86813 56558;86820 56648;86813 56760 32;86805 56992 33;86790 57315;86790 57518;86708 57840 1;86685 57908;86633 57975;86580 57990 32;86565 58043 33;86445 58253;86363 58373;86198 58560 1;85958 58845;85943 59063;85875 59423 32;86558 59753 32;87240 60030 32;87270 59948 33;87315 59790;87413 59640;87570 59685 1;88035 59850;88283 59895;88755 60075 1;88905 60143;88980 60262;89003 60420 32;89438 60427 32;89445 60315 33;89453 59835;89430 59558;89385 59033 1;89355 58808;89303 58665;89415 58455 1;89543 58215;89685 58073;89835 57832 1;89880 57750;89865 57615;89775 57578 1;89295 57398;88920 57488;88492 57218 1;88313 57113;88290 56955;88260 56745 1;88133 56010;87975 55635;87923 54915;87878 54787 18;90735 52568 1;91140 52537;91358 52455;91710 52238 1;92250 51908;92468 51653;93008 51300;81742 56325;82470 57060 32;83235 57630 32;83310 57563 33;83340 57525;83370 57495;83415 57435 1;83453 57383;83528 57412;83580 57450 1;83775 57623;83933 57630;84135 57795 1;84195 57855;84262 57773;84323 57713 1;84548 57480;84593 57308;84810 57052 32;84810 56843 32;84900 56768 33;84930 56753;84960 56745;85005 56723 1;85605 56483;85898 56295;86543 56213 1;86580 56213;86625 56220;86655 56235 32;86843 54998 32;86348 54983 32;84983 54735 32;84555 54585 32;83295 54150 32;82875 54015 32;81548 53603 32;81495 53490 32;81495 53610 33;81495 53670;81503 53715;81518 53775 1;81578 54158;81690 54330;81720 54705 1;81735 54975;81630 55110;81630 55373 1;81623 55537;81765 55598;81765 55755 1;81758 55943;81750 56040;81750 56205;81742 56325 18;84833 56933 1;84810 57060;84855 57188;84983 57218 1;85380 57330;85620 57353;85943 57608 1;86153 57780;86288 57818;86512 57975 1;86588 58035;86678 57938;86708 57840 1;86805 57480;86790 57278;86813 56895 1;86820 56707;86828 56610;86798 56423 1;86768 56295;86670 56198;86543 56213 1;85898 56295;85605 56483;85005 56723 1;84893 56768;84833 56783;84810 56895;93023 59205;97297 56655 1;97283 56625;97275 56588;97283 56535 1;97283 56378;97238 56302;97260 56137 1;97275 55995;97297 55898;97425 55808 1;97538 55733;97620 55755;97755 55718 1;97883 55688;97950 55523;97890 55403 1;97800 55245;97680 55223;97515 55140 1;97455 55117;97403 55088;97365 55050 32;97320 54975 32;97320 54818 33;97335 54668;97380 54578;97425 54412 32;97462 54300 33;97493 54195;97508 54143;97545 54037 1;97643 53738;97755 53520;98063 53423 1;98160 53393;98235 53378;98318 53378 32;98415 53355 1;98258 53205;98198 53063;97988 53003 1;97913 52988;97905 52867;97965 52815 1;98070 52725;98145 52650;98167 52515 32;98175 52425 32;97305 52335 32;96683 52268 32;95385 52140 32;94778 52103 32;94725 52155 32;95242 52927 32;94965 53228 32;93908 53168 32;93525 52343 32;93503 52260 32;93413 52260 32;92955 52343 32;91680 52762 32;91133 52980 33;91208 53130;91223 53213;91298 53355 1;91320 53423;91365 53453;91440 53453 1;91583 53453;91658 53438;91808 53438 1;91883 53438;91935 53505;91943 53580 1;91958 53835;92003 53955;92085 54195 1;92175 54495;92310 54608;92483 54863 1;92520 54923;92475 54998;92415 55020 32;92880 59205;93023 59205 18;97275 56625;92977 59175 32;93015 59220 32;93083 59332 32;93510 60045 32;94635 60105 32;94650 60023 33;94665 59798;94650 59490;94867 59490 32;95018 59385 33;95318 59355;95460 59332;95835 59235 1;96413 59108;96750 58845;96968 58313 1;97208 57713;97260 57360;97290 56723;97275 56625 18;103433 60600;103823 59543 1;103658 59475;103515 59400;103387 59512 1;103163 59700;103133 59768;103005 60023 1;102885 60255;102503 60503;102292 60668;103433 60600 18;78615 77933 1;78630 77843;78645 77753;78668 77655 1;78810 76950;78945 76605;78990 75870 1;79005 75293;78990 74385;79545 74535 1;80250 74730;80528 75060;81030 75593 1;81375 75975;81727 76020;82245 76012 1;82590 76012;82867 76050;83085 75773 1;83220 75600;83528 75683;83625 75870 1;83835 76343;84000 76553;84367 76913 1;84795 77363;85073 77640;85463 77955;92175 77970 1;92438 77730;92678 77483;92948 77093 1;93480 76305;93885 76005;94568 75315 1;95205 74655;95775 74625;96645 74295 1;97260 74063;97650 73815;98265 73590 1;98505 73515;98505 73275;98190 72953 1;97988 72773;97950 72510;98085 72270 1;98198 72083;98348 72060;98505 71895 1;98715 71670;98887 71520;99210 71535 1;99458 71550;99540 71730;99750 71895 1;100320 72352;100545 72660;101167 73050 1;101775 73455;102060 73695;102727 73995 1;103725 74460;104295 74790;105405 74715 1;106140 74670;106590 74730;107205 74310;73275 77528 1;73403 76950;73688 76523;73710 75795 1;73718 75030;73230 74730;72750 74130 1;72165 73433;71685 73043;71685 72135 1;71685 71715;71715 71430;72008 71115 1;72637 70425;73500 70575;74370 70950 1;75135 71303;75578 71415;76268 71910 1;76770 72285;76995 72540;77588 72735 1;78578 73073;79095 73245;80025 73733 1;80940 74220;81338 74670;82365 74835 1;82740 74903;83010 74775;83227 74453 1;83385 74213;83670 74010;83925 74175 1;84240 74385;84367 74602;84450 74970 1;84570 75593;84570 75990;85005 76433 1;85538 76980;85778 77303;86408 77730 1;86535 77820;86648 77895;86760 77963;91343 77963 1;91755 77565;91898 77250;92325 76793 1;92790 76290;92955 75975;93225 75330 1;93510 74655;93660 74265;94208 73755 1;94680 73320;95108 73410;95708 73170 1;96420 72893;96690 72563;97268 72053 1;97958 71445;98318 71130;98910 70410 1;99008 70283;99188 70305;99330 70395 1;99870 70800;100118 71040;100688 71415 1;101528 71970;101940 72270;102810 72795 1;103470 73200;103905 73185;104670 73335 1;105540 73515;105998 73575;106890 73470 1;107280 73350;107528 73313;107813 73005;92970 77970 1;93548 77288;93953 76793;94748 76095 1;95738 75225;96540 75210;97808 74790 1;98385 74602;98820 74505;99105 73950 1;99225 73710;99278 73590;99390 73335 1;99488 73095;99840 73095;100050 73253 1;100650 73733;100935 73995;101625 74333 1;102555 74813;103080 74963;104108 75173 1;104977 75360;105420 75585;106305 75510 1;106837 75473;107130 75435;107625 75210 1;107993 75038;108045 74730;108172 74333 1;108360 73733;108480 73148;109110 73058 1;109688 72983;110025 72998;110558 73245 1;110970 73448;111248 73583;111428 74003 1;111623 74475;111600 74745;111667 75248 1;111690 75480;111743 75675;111968 75742 1;112208 75818;112335 75803;112605 75833;113160 53250;113565 52305;113468 53550;113820 52403 1;113587 52268;113393 52320;113145 52403 1;112980 52463;112935 52620;112913 52785 1;112860 53093;112868 53250;112852 53558;113468 53550 18;113520 53198;113828 52410 33;113550 52215;113250 52373;113145 52403 1;112980 52463;112935 52620;112913 52785 1;112890 52920;112875 53025;112868 53123 32;112852 53250 32;113137 53205;113520 53198 18;114255 50985;112950 51758;112583 51037;114893 49957;114533 49335 1;114435 49500;114398 49590;114270 49725 1;114188 49815;114090 49808;113985 49778 1;113602 49680;113408 49575;113018 49582 1;112785 49590;112605 49628;112508 49823 1;112268 50280;112230 50543;112125 51037 1;112087 51195;112350 51188;112500 51128 1;113378 50798;113738 50438;114623 50093 1;114743 50048;114825 50048;114930 49950 1;115140 49748;115238 49582;115245 49283 1;115245 49170;115102 49140;114990 49140;114533 49335 18;111225 53512;112005 53363 1;112193 53302;112020 53198;112035 53010 1;112035 52875;112012 52853;111990 52710 1;111878 52155;111938 51825;112155 51293 1;112208 51165;112403 50963;112080 50940 1;111750 50918;111563 51075;111375 51338 1;111068 51773;111210 52117;111225 52643 1;111233 53093;110955 53287;110625 53573;111225 53512 18;112868 53168 33;112875 53055;112883 52935;112913 52785 1;112935 52620;112980 52463;113145 52403 1;113363 52335;113542 52283;113738 52365 32;113880 52380 1;114292 51465;114563 51023;114863 50055 1;114893 49957;114698 50048;114608 50085 1;113940 50408;113618 50588;112950 50887 1;112703 51000;112560 51075;112297 51098 1;112133 51120;112073 51278;112035 51427 1;111953 51698;111960 51848;111938 52117 1;111885 52575;112005 52815;112155 53242;112868 53168 50;118710 48150 32;118643 47520 32;119760 47453 32;120030 47355 1;119962 47048;119723 46912;119415 46845 1;119100 46785;118890 46853;118643 47040 1;118065 47475;117705 47595;117060 47895 1;116797 48023;116700 48203;116663 48480;118710 48150 50;115178 49207 1;115238 49207;115290 49177;115297 49110 1;115305 48975;115395 48923;115440 48787 1;115462 48705;115583 48585;115500 48578 1;115095 48555;114840 48795;114675 49162;115178 49207 18;106943 55170 33;107385 54832;107708 54660;107962 54533 32;108098 54375 1;107977 54113;107917 53940;107685 53768 1;107580 53700;107535 53610;107550 53483 1;107558 53348;107587 53258;107528 53130 1;107422 52943;107205 53018;106988 53033 1;106553 53078;106365 53265;105938 53302 1;105593 53340;105383 53280;105098 53460 1;104910 53580;104962 53873;105135 54000 1;105368 54188;105510 54255;105803 54338 1;106297 54488;106462 54802;106725 55253;106943 55170 50;108262 56348 1;108705 56430;108938 56370;109387 56385 1;109538 56393;109635 56220;109605 56063 1;109500 55628;109440 55403;109297 54975 1;109223 54780;109133 54623;108922 54593 1;108743 54570;108653 54653;108518 54758 1;108300 54930;108255 55073;108045 55238 1;107933 55328;107828 55373;107813 55508 1;107775 55748;107775 55867;107760 56100;108262 56348 18;107685 56242 1;107145 56558;106733 56528;106328 56985 1;106185 57150;106148 57255;106058 57450 1;105938 57698;105908 57870;105690 58020 1;105547 58117;105495 58238;105518 58403 1;105547 58778;105465 59145;105113 59242 1;104775 59340;104587 59280;104265 59385 1;104033 59468;103973 59617;103845 59820 1;103672 60090;103613 60248;103508 60540 1;103470 60637;103560 60720;103658 60735 1;104100 60840;104333 60818;104783 60923 1;104977 60975;105068 61028;105278 61035 1;105540 61050;105720 61103;105945 60945 1;106538 60533;106845 60315;107295 59738 1;107595 59348;107738 59137;107925 58673 1;108045 58373;108180 58193;108495 58073 1;108720 57990;108953 58035;109035 57802 1;109102 57585;109178 57473;109178 57233 1;109163 56910;108900 56760;108593 56655 1;108413 56603;108337 56543;108165 56483;107685 56242 18;106508 56880 1;106305 56550;106230 56363;105960 56085 1;105885 56018;105833 56198;105833 56287 1;105788 56940;105765 57323;105405 57855 1;105285 58028;105240 58133;105098 58275 1;104730 58643;104618 58898;104318 59310 1;104273 59378;104385 59445;104460 59430 1;104887 59385;105278 59453;105473 59063;106508 56880 18;107078 56040;106680 55935 32;105915 55635 32;105960 56085 33;106178 56318;106268 56490;106410 56723 32;106440 56783 32;106508 56880 32;107738 56265;107078 56040 18;107520 56332 33;107055 56558;106688 56580;106328 56985 1;106185 57150;106148 57255;106058 57450 1;105938 57698;105908 57870;105690 58020 1;105547 58117;105495 58238;105518 58403 1;105547 58778;105465 59145;105113 59242 1;104858 59318;104693 59302;104498 59332;107768 55935 33;107775 55800;107783 55688;107813 55508 1;107828 55373;107933 55328;108045 55238 1;108255 55073;108315 54915;108533 54742 1;108585 54705;108495 54765;108547 54735;109365 55230 1;109665 54870;109875 54735;110212 54390 1;110288 54315;110273 54143;110167 54120 1;109883 54068;109755 53985;109500 53865 1;109275 53768;109125 53835;108900 53903 1;108675 53978;108630 54128;108473 54293 1;108420 54345;108330 54353;108352 54412 1;108398 54578;108443 54660;108533 54802;109365 55230 18;111698 56490 1;111585 55853;111608 55598;111518 54998 1;111443 54578;111675 54008;111255 53963 1;111105 53955;111083 54135;111038 54270 1;110843 54818;110745 55110;110378 55545 1;110190 55762;110040 55845;109928 56100 1;109868 56228;110040 56318;110175 56325 1;110602 56370;110820 56393;111225 56550;111698 56490 18;109477 57503 1;109515 57555;109620 57585;109643 57518 1;109688 57345;109710 57255;109725 57075 1;109733 56933;109875 56760;109740 56715 1;109410 56625;109230 56648;108900 56633;109477 57503 18;106628 61133 1;106898 60855;107040 60645;107430 60585 1;107760 60540;107955 60533;108233 60330 1;108420 60188;108570 60180;108818 60188 1;108983 60195;109028 60045;109133 59903 1;109268 59707;109275 59565;109313 59318 1;109403 58650;109605 58328;109583 57645 1;109575 57548;109462 57548;109395 57473 1;109313 57405;109275 57308;109178 57330;109155 57443 33;109125 57563;109080 57660;109035 57802 1;108953 58035;108720 57990;108495 58073 1;108180 58193;108045 58373;107925 58673 1;107738 59137;107595 59348;107295 59738 1;106845 60315;106538 60533;105945 60945 1;105870 60998;105795 61028;105727 61043 32;105870 61140;106628 61133 18;105945 60945 33;106538 60533;106845 60315;107295 59738 1;107595 59348;107738 59137;107925 58673 1;108045 58373;108180 58193;108495 58073 1;108720 57990;108953 58035;109035 57802 1;109073 57683;109110 57600;109133 57503;108023 61365;108818 60188 33;108570 60180;108420 60188;108233 60330 1;107955 60533;107760 60540;107430 60585 1;107055 60645;106905 60840;106658 61095 32;106635 61162 32;107970 61463;108023 61365 18;112875 53603;112875 53250 33;112598 53258;112358 53258;112125 53295 1;111833 53355;111608 53475;111345 53558 32;111172 53670 1;111195 53783;111218 53828;111248 53933;112875 53603 18;109395 55290 33;109470 55545;109523 55748;109605 56063 1;109635 56220;109538 56393;109387 56385 1;109065 56378;108855 56408;108608 56393;109598 57525 1;109448 57383;109320 57188;109148 57285 1;108840 57457;108428 57780;108675 58020 1;108922 58275;109095 58350;109425 58478;109598 57525 18;109365 61425;109410 60930 32;109762 60908;109883 61253;109898 61508;109470 60983;109433 61718 32;109830 61740 32;109770 60968;109470 60983 18;111983 62662;111990 63525 32;112538 63503 32;112830 62873;112073 62520;112050 63465 32;112485 63435 32;112830 62662;112073 62520 18;116640 63818;116670 64567 32;117698 64537;116730 63555;116730 64500 32;117885 64440;116730 63555 18;122198 65310;122265 66060 32;122723 66015 32;122648 65273 32;122198 65310 18;121718 65093;121748 65535 32;122625 65468 32;122745 65033;121792 64860;121823 65460 32;122558 65408 32;122723 64800;121792 64860 18;124485 56730;121238 57135;121628 59468;123300 59235 1;123255 58973;123210 58800;123000 58635 1;122745 58455;122550 58433;122250 58455 1;121920 58485;121733 58635;121560 58912;121628 59468 18;123068 57008 1;123225 57195;123390 57262;123637 57225 1;123870 57195;123990 57090;124133 56887;123068 57008 18;121462 57908 1;121672 57675;121778 57495;121762 57173;121358 57218;121462 57908 18;121560 58912 1;121733 58635;121920 58485;122250 58455 1;122550 58433;122745 58455;123000 58635 1;123210 58800;123255 58973;123300 59235;123132 57085 1;123289 57272;123390 57262;123637 57225 1;123870 57195;123926 57205;124069 57002;121564 57793 1;121774 57560;121778 57661;121762 57339;124485 56745;121320 57165;121560 59505 32;124485 59145;124493 56745;124485 56745 18;124058 54427;123990 53738;122415 54832;122795 54795;122693 53723 16;121538 54427;121500 53895;124493 53610;124050 53498;124133 54383 32;124500 54360;124500 53610;124493 53610 18;121568 53617;121643 54840 32;122738 54750 32;122580 53498;121568 53617 18;121635 53048;121620 52845 32;121380 52823 32;121365 51787 32;119820 51030 32;119887 50693 32;119025 50430 32;117938 50468 32;117637 50108 32;116955 50130 32;116790 50595 32;116903 51218 32;117555 51555 32;118297 51570 32;118590 51810;120922 53198;120915 52110 32;119723 51540 32;119460 51728;121568 53400;121538 52898 32;121358 52853 32;121328 51750 32;120113 51120 32;119813 50677 32;119093 50423 32;117953 50460 32;117840 50363 32;117637 50108 32;116955 50130 32;116790 50595 32;116903 51218 32;117555 51555 32;118297 51570 32;118553 51787 32;119468 51765 32;119678 51570 32;121005 52140 32;121005 53453;121568 53400 18;118095 54555;117090 54623 32;117120 55335;118950 54878;119047 55957;119602 55808;119955 55785 32;119910 55238 32;119558 55260 32;119602 55808 18;119640 55328;119565 54563;118283 54637;117165 54705 32;117225 55478;118283 54637 18;119910 55283;119858 54473 32;119573 54593 32;119648 55343;119910 55283 18;119010 54608;119123 55838 32;119610 55778 32;119468 54360;119010 54608 18;116753 55568;115020 55740 32;115058 56153 32;116273 56033;115485 56130;115553 57000;117023 55628;115087 55793 32;115118 56115 32;115545 56085 32;115672 57278;117023 55628 18;115125 58718;113212 58912 32;113235 59130 32;115140 58898;115125 58718 18;114998 60488;114308 60585 32;114352 61088 32;115080 60990;117135 57098;116640 57630 32;116145 57600;116318 61973;116512 61710 32;117045 61650;115253 60540;114375 60637 32;114398 61005 32;115320 60878;115253 60540 18;115988 57503;116618 57555 32;117030 57113 32;116528 56670;115988 57503 18;116925 63300;117210 62963 32;117023 61695 32;116565 61762 32;116183 62310;116925 63300 18;124493 54427;124080 54465 32;123990 53760 32;122670 53670 32;122783 54795 32;121590 54908 32;121508 53873 32;120600 54158 32;120908 57143 32;124493 56760;124500 54427;124493 54427 18;124477 59153;121545 59543 32;121395 58380 32;120360 58463 32;120075 55853 32;119018 55890 32;118935 54923 32;117810 55695 32;116693 56730 32;117083 57105 32;116693 57563 32;116010 57608 32;115658 58748 32;115808 60600;116227 62048;116468 61785 32;117045 61650 32;117330 62992 32;117262 63300 32;117922 63870 32;119415 64335 32;122408 64335 32;124470 63818;124485 59153;124477 59153 18;100193 40162 1;99727 39803;99480 39630;98970 39330 1;98505 39060;98227 38895;97988 38415 1;97380 36720;96795 35790;97028 34020;110587 34073 1;110715 34155;110850 34238;111000 34320 1;111630 34703;111998 34815;112672 35115 1;112792 35175;112845 35295;112808 35423 1;112448 36510;112245 37103;112365 38235;91136 40984;91114 41531 32;91586 41554 32;91601 41006 32;91136 40984 18;100184 42976;101369 43231 32;101466 42758 32;100274 42503 32;100184 42976 18;109995 39923;111188 39878 32;111150 39045 32;110310 39082 32;110318 39420 32;109973 39443 32;109995 39923 18;121193 58320;121365 58298 32;121260 57255 32;121080 57278;121193 58320 18;116385 44813;116280 46785 1;114150 46890;113070 46860;111000 47332 1;110190 47520;109792 47610;108990 47798 1;108810 47843;108758 47940;108630 48060;99750 44610 1;100170 44700;100613 44805;101167 44933 1;101925 45120;102315 45293;102968 45728 1;103433 46035;103553 46125;104025 46193 1;104895 46328;105398 46380;106328 46388 1;108885 46433;110063 45938;112620 45720;109185 48300 1;109628 48338;109852 48405;110295 48353 1;110393 48345;110520 48315;110505 48210 1;110453 47978;110295 47835;110055 47798 1;109740 47753;109448 47707;109283 47970 1;109208 48090;109110 48158;109155 48278;109185 48300 18;107280 48968 1;107483 48960;107640 48848;107633 48728 1;107633 48615;107498 48473;107295 48488 33;107100 48495;106905 48653;106913 48765 1;106913 48885;107085 48983;107280 48968 18;107738 47759;105855 47856;92348 50498 1;92183 50475;92123 50378;91965 50378 1;91860 50385;91808 50490;91755 50573 1;91590 50828;91598 50992;91470 51255 1;91403 51383;91500 51510;91635 51563 1;91785 51630;91928 51630;92040 51503 1;92250 51255;92265 51060;92348 50738 1;92370 50648;92430 50520;92340 50490;92348 50498 18;93578 52223 1;93540 52020;93510 51637;93308 51668 1;93038 51713;92910 52170;92850 52425;93578 52223 18;84203 50093 1;84285 50242;84495 50145;84623 50025 1;85110 49552;85230 49207;85665 48683 1;85755 48578;85710 48383;85575 48330 1;85170 48195;84945 48195;84540 48082 1;84405 48052;84308 48052;84210 48143 1;84045 48300;84000 48405;83843 48563 1;83678 48728;83640 48923;83730 49133 1;83880 49523;84015 49695;84188 50070;84203 50093 18;83498 48870 33;84225 49193;84660 49365;85793 49650 1;86153 49740;86325 49695;86685 49815 1;87788 50205;88230 50565;89310 51015 1;90113 51360;90585 51653;91110 52193 32;91305 52320 1;91643 52185;91778 52043;92093 51840 1;92242 51750;92235 51600;92235 51412;92190 51270 33;92153 51353;92108 51427;92040 51503 32;91980 51555 33;91883 51630;91755 51623;91635 51563 1;91500 51510;91403 51383;91470 51255 1;91568 51052;91583 50903;91673 50723 32;91710 50610 1;91418 50498;91260 50468;90960 50385 1;89820 50108;89242 49995;88080 49912 1;87968 49905;87878 49830;87885 49718 1;87893 49560;87870 49478;87863 49313 1;87840 49095;87690 48983;87488 48908 1;86940 48720;86655 48668;86108 48518 1;85762 48427;85755 48090;85433 47940 1;85223 47850;85110 48105;84893 48082 1;84690 48068;84578 47993;84398 48060 1;83918 48255;83745 48480;83355 48795;83498 48870 50;83610 44588 1;84308 44760;84698 44768;85410 44625;88328 44423 1;87803 43800;87360 43508;87233 42698;95670 46875 1;95588 46770;95550 46710;95475 46598 1;95438 46568;95400 46545;95363 46553 1;95318 46553;95280 46568;95250 46598 1;95130 46710;95025 46733;94973 46875 1;94943 46943;94935 47003;94935 47048 1;94935 47115;94943 47175;95003 47220 1;95063 47303;95085 47363;95183 47400 1;95288 47460;95378 47430;95498 47370 1;95573 47332;95617 47295;95700 47235 1;95730 47220;95753 47183;95753 47138 1;95760 47108;95745 47070;95738 47018 1;95708 46973;95693 46943;95670 46890;95670 46875 18;94950 46957 1;94733 47152;94455 47190;94313 47363 1;94253 47445;94313 47745;94403 47783 1;94523 47843;94867 47820;94995 47768 1;95175 47700;95205 47543;95325 47378;94950 46957 18;102893 47858 1;103012 47895;103020 47978;103028 48037 1;103073 48248;103118 48465;103313 48540 1;103545 48653;103733 48555;103965 48443 1;104167 48360;104295 48420;104520 48480 1;104678 48533;104850 48488;104910 48653 1;104948 48773;104993 48930;105135 48960 1;105278 48998;105323 48945;105443 48848 1;105547 48765;105683 48653;105788 48555;103755 47100 1;103417 46853;103215 46777;102840 46598 1;102637 46508;102525 46500;102315 46455 1;101873 46380;101633 46500;101212 46628 1;100823 46748;100620 46868;100320 47138 1;100238 47213;100387 47348;100500 47332 1;100643 47318;100718 47250;100860 47280 1;101610 47460;101970 47595;102720 47805 1;103178 47940;103380 47505;103762 47213;103755 47100 18;105741 43279;105210 46148 32;103665 45893;102345 45045;97583 44123 32;92226 43370 32;89579 43106;88851 42674 32;88282 41889;88302 41376;89016 40811;89808 40565;92475 40692 32;97361 41391;97728 41725;101055 42329 32;105741 43279 18;98346 43880;98429 43490 32;98031 43422 32;97949 43797 32;98346 43880 18;97299 43761;97382 43356 32;96969 43281 32;96887 43679 32;97299 43761 18;95595 34020;95400 35513;95438 36923 32;95460 37560;96165 39255;95850 39795 32;88463 39450 32;88497 37321 32;88508 36630;88538 35287;88628 34755;88755 33998;92595 37245;93075 37253 32;93098 36405 32;92617 36405 32;92595 37245 18;96122 41205;96225 40418 32;90075 40125 32;90009 40568 32;92498 40628;96122 41205 18;93698 39735;93713 40110 32;95895 40125 32;95858 39840;93698 39735 18;109140 44588 1;109118 44813;109118 44918;109125 45135 1;109125 45293;109245 45412;109403 45412 1;109590 45412;109688 45428;109883 45420 1;109988 45420;110063 45285;110025 45180 1;109950 45008;109860 44948;109733 44813;109140 44588 18;109140 44753 1;109118 44978;109118 44918;109125 45135 1;109125 45293;109245 45412;109403 45412 1;109590 45412;109688 45428;109883 45420 1;109988 45420;110063 45285;110025 45180 1;109950 45008;109980 45053;109852 44918;106343 43290 1;106320 43425;106350 43537;106470 43598 1;107220 44025;107580 44295;108390 44618 1;108547 44685;108750 44655;108795 44483 1;108803 44430;108712 44460;108667 44430 1;108345 44258;108165 44198;107828 44055 1;107663 43995;107587 43950;107438 43868;106343 43290 18;106335 43380 1;106335 43478;106373 43553;106470 43598 1;107220 44025;107580 44295;108390 44618 1;108503 44670;108637 44670;108720 44603;108488 44633;109148 44948 32;109125 44595 32;108727 44430;108488 44633 18;109635 46050 1;109792 45863;109935 45803;110190 45743 1;110422 45698;110535 45593;110685 45398 1;110768 45293;110753 45203;110753 45060 1;110745 45015;110685 45037;110640 45023 1;110310 44955;110145 44925;109823 44835;109868 44955 33;109928 45015;109980 45082;110025 45180 1;110063 45285;109988 45420;109883 45420 1;109688 45428;109590 45412;109403 45412 1;109343 45412;109297 45405;109253 45375 32;109020 45435 33;108840 45405;108675 45330;108533 45330 1;108323 45338;108150 45495;107962 45495 1;107587 45503;107190 45398;106695 45398 1;106553 45398;106470 45338;106387 45225 1;106305 45135;106350 45113;106320 44993 1;106283 44873;106005 44873;105983 44993 1;105945 45173;105968 45383;105983 45563 1;105990 45728;106073 45855;106238 45870 1;106538 45915;106688 45923;106995 45945 1;107243 45968;107393 46080;107520 46298 32;107805 46268;109635 46050 18;110378 45660 1;110903 45638;111165 45593;111698 45540 1;111825 45533;112080 45540;112005 45435 1;111900 45308;111803 45270;111645 45233 1;111262 45150;111083 45060;110700 45023;110378 45660 18;105225 46245;106380 46313 32;107520 46298 33;107393 46080;107243 45968;106995 45945 1;106688 45923;106538 45915;106238 45870 1;106073 45855;105990 45728;105983 45563 1;105968 45383;105960 45285;105998 45105 1;106020 44985;106283 44985;106320 45105 1;106350 45225;106305 45308;106387 45398 1;106470 45510;106575 45495;106718 45495 1;107212 45495;107587 45503;107962 45495 1;108150 45495;108323 45338;108533 45330 1;108675 45330;108840 45405;109020 45435 32;109110 45412 32;109193 45330 33;109148 45277;109125 45210;109125 45135 1;109118 45068;109140 44993;109140 44940 32;108698 44693 32;108593 44655 32;108525 44655 33;108480 44655;108428 44640;108390 44618 1;107633 44325;107273 44070;106620 43688 32;106575 43643 33;106283 43755;106087 43800;105825 43920 32;105675 43950 32;105180 46193;105225 46245 18;110475 43515 1;110348 43980;110303 44265;110205 44730 1;110160 44925;110393 45000;110587 45045 1;110775 45098;110873 45120;111075 45120 1;111218 45120;111405 45248;111435 45090 1;111503 44662;111585 44332;111683 43860;110475 43515 18;109148 43770;106815 41858;106417 41910 33;106515 42120;106590 42225;106733 42420 1;106883 42660;106995 42690;107273 42735 1;107498 42780;107678 42457;107917 42488 1;108172 42533;108195 42930;108458 42893 1;108660 42870;108735 42848;108833 42818 32;109058 42750 1;109223 42698;109223 42525;109238 42345 1;109245 42113;109058 42023;108870 41880;106815 41858 18;103305 42098 33;103583 42412;104280 42615;104955 42720 1;104977 42728;105000 42735;105023 42735 32;105180 42683 1;104948 42308;104723 42203;104430 41873;103305 42098 50;105458 41880 1;105578 42180;105533 42375;105720 42638 1;105803 42773;105900 42832;106058 42840 1;106462 42870;106635 43050;107025 43193 1;107625 43433;107873 43703;108458 43980 1;108615 44063;108840 43868;108885 43695 1;108975 43298;108990 43095;109118 42698 1;109163 42548;108878 42660;108727 42630 1;107783 42465;107348 42233;106455 41918;105458 41880 18;109448 41498;109477 40680 32;107775 40620 32;107730 41588;109448 41498 18;97508 40680 1;97433 40418;97395 40283;97297 40020 1;97230 39863;97020 39900;96870 39983 1;96698 40080;96428 40275;96593 40373;97508 40680 18;99803 41287 1;99998 41310;100087 41363;100290 41385 1;101340 41535;101843 41820;102915 41835 1;103035 41843;103238 41835;103200 41715 1;103073 41332;102795 41018;102510 40793 1;102315 40658;102128 40673;101948 40620 1;101355 40440;100800 40590;100073 40418 1;99863 40373;99750 40410;99540 40388 1;99180 40358;99023 40223;98670 40223 1;98363 40223;98325 40545;98167 40800;99803 41287 18;106852 41565 1;106845 41310;106778 41183;106665 40950 1;106613 40853;106590 40748;106485 40740 1;106290 40733;106200 40725;106012 40725 1;105765 40725;105630 40635;105413 40718 1;105308 40763;105285 40845;105270 40950 1;105240 41152;105255 41258;105248 41460;106852 41565 18;106635 41543;107797 41550 32;107843 40650 32;106485 40703;106635 41543 18;102278 40650;103148 41760 32;104348 41460 32;105278 41445 32;105390 40718 32;103215 40740 32;102683 40703;102278 40650 18;103598 42698 1;103628 42615;103620 42563;103650 42465 1;103695 42308;103485 42270;103335 42203 1;103012 42068;102803 42105;102465 42158 1;102240 42195;102135 42255;101925 42308;103598 42698 18;117540 45810 1;114900 45548;113212 45443;110587 44902 1;109238 44633;107730 43890;107063 43560 1;106095 43065;106170 42923;104955 42720 1;104220 42600;103455 42368;103245 42000;119198 43943;124530 43718;103035 45832 1;103538 45908;103913 45968;104550 45975 1;105608 45990;106125 45803;107167 45555 1;108075 45345;108518 45000;109470 45015 1;110520 45030;110985 44580;112005 44273 1;112890 44010;113318 43815;114210 43553 1;115095 43290;115568 43170;116505 43155 1;117450 43140;117930 43125;118868 42930 1;119850 42743;120315 42533;121245 42135 1;122310 41670;123068 41543;123690 40553 1;124073 39938;124530 39645;124545 38925;124538 38925 1;124530 38310;124462 37845;123968 37613 1;123225 37290;122685 37365;122145 36773 1;121575 36165;121545 35670;121245 34890 1;121118 34590;121042 34328;120938 34095;110880 45870 1;111315 45638;111690 45428;112305 45233 1;113955 44700;114788 44370;116505 44093 1;117780 43890;118440 43905;119685 43553 1;120750 43260;121260 43013;122288 42593 1;123248 42218;123818 41933;124538 41453;124545 37350 1;124365 37268;124170 37178;123945 37050 1;123210 36660;122580 36503;122348 35693 1;122198 35183;122190 34912;121988 34410 1;121935 34298;121883 34193;121830 34095;113865 46080 1;114053 45975;114248 45855;114495 45705 1;115215 45285;115590 45000;116415 44820 1;117465 44603;118020 44550;119100 44423 1;121328 44160;122288 43695;124448 42795;124538 42773;124545 36488 1;123570 36015;122925 35468;122648 34350 1;122618 34260;122587 34178;122558 34103;74145 38430 1;73950 38055;73710 37950;73350 37725 1;73073 37568;72870 37613;72563 37650 1;72315 37688;72135 37478;72128 37230 1;72105 37058;72053 37043;71813 37035 1;71655 37035;71588 37140;71512 37268 1;71445 37373;71378 37463;71265 37433 1;71078 37388;70980 37395;70808 37335 1;70665 37298;70305 37268;70283 37628 1;70260 37950;70538 38078;70703 38070;74145 38430 18;70770 38093;70538 37148 32;69503 37890;70770 38093 18;70335 37748 1;70313 37703;70298 37658;70305 37605 1;70313 37463;70560 37193;70808 37335 1;70965 37418;71078 37388;71265 37433 1;71378 37463;71445 37373;71512 37268 1;71588 37140;71655 37035;71813 37035 1;72053 37043;72105 37058;72128 37230 1;72135 37478;72315 37688;72563 37650 1;72870 37613;73073 37568;73350 37725 1;73665 37928;73890 38033;74078 38318;74310 33945 1;73943 34118;73718 34238;73395 34530 1;72367 35460;71655 36075;70838 36750 1;70748 36825;70650 36900;70538 36983;70448 37125;70560 37320 32;70688 37335 33;70725 37328;70762 37328;70808 37335 1;70980 37395;71078 37388;71265 37433 1;71378 37463;71445 37373;71512 37268 1;71588 37140;71655 37035;71813 37035 1;72053 37043;72105 37058;72128 37230 1;72135 37478;72315 37688;72563 37650 1;72870 37613;73073 37568;73350 37725 1;73643 37912;73860 38018;74040 38265 32;74175 38483 32;76815 38385 32;76913 38108 33;77033 37515;77288 37140;77430 36443 1;77610 35483;77790 34740;77850 33960;74310 33960;74310 33945 18;77558 35498 1;77738 35527;77835 35535;78023 35573 1;78158 35603;78315 35603;78420 35498 1;78563 35355;78600 35198;78570 34988 1;78503 34628;78593 34545;78450 34200 1;78413 34118;78233 34103;78143 34095 1;78023 34095;77948 34103;77835 34103;77558 35498 18;79913 33975 1;79875 34027;79838 34080;79800 34140 1;79718 34260;79545 34230;79448 34133 1;79328 34035;79238 34020;79133 33968;77820 33968;77813 34125 1;78045 34118;78038 34103;78120 34103 1;78210 34110;78338 34155;78375 34238 1;78518 34582;78503 34628;78570 34988 1;78600 35198;78548 35340;78405 35483 1;78323 35565;78233 35580;78135 35565 32;77918 35543 32;77483 35408 1;77423 35408;77385 35415;77355 35453;77355 35828 1;77963 35888;78262 35948;78878 35978 1;79088 35993;79215 35970;79410 36060 1;79545 36128;79635 36203;79658 36353 1;79695 36705;79725 36878;79740 37223 1;79740 37380;79852 37568;80003 37508 1;80205 37440;80273 37305;80378 37110 1;80505 36863;80565 36735;80685 36473 1;80753 36308;80865 36263;81015 36158 1;81218 36015;81330 35963;81548 35828 1;81690 35745;81893 35707;81968 35858 1;82043 36015;82005 36113;82088 36263 1;82125 36360;82193 36510;82290 36465 1;82425 36412;82583 36270;82583 36113 1;82583 35902;82500 35805;82418 35603 1;82313 35370;82230 35250;82245 34988 1;82245 34920;82193 34868;82125 34860 1;81727 34838;81525 34793;81135 34777 1;80985 34777;80865 34815;80723 34793;80573 34763 33;80400 34680;80348 34673;80250 34598 1;80130 34523;80145 34245;80242 34140 1;80280 34095;80310 34043;80340 33998 32;80288 33975;79913 33975 18;81360 34770 1;81352 34808;81383 34838;81420 34838 1;81600 34868;81698 34883;81893 34868 1;81960 34868;81983 34823;82035 34770 1;82117 34688;82125 34568;82058 34463 1;81938 34298;81727 34373;81548 34463 1;81413 34537;81390 34650;81383 34800;81360 34770 18;83250 35798 1;83400 35933;83595 35963;83670 35873 1;83745 35790;83693 35603;83543 35468 33;83393 35340;83198 35303;83130 35393 1;83048 35483;83100 35670;83250 35798 18;83063 33983 1;83108 34058;83145 34140;83168 34253 1;83168 34298;83175 34373;83220 34350;83258 34365 1;83363 34305;83468 34275;83573 34343 1;83633 34388;83708 34425;83760 34365 1;83828 34290;83805 34185;83738 34103 1;83693 34058;83648 34013;83602 33975;83055 33983;83063 33983 18;81765 33983;81908 34380 1;81968 34388;82012 34418;82058 34463 1;82125 34568;82117 34688;82035 34770 32;81953 34853 33;82005 34860;82065 34860;82125 34860 32;82230 34890 1;82275 34725;82395 34688;82530 34575 1;82658 34470;82762 34455;82935 34470 1;83108 34493;83063 34703;83175 34838 1;83235 34920;83333 34912;83423 34860 1;83528 34793;83355 34673;83265 34575 1;83205 34515;83168 34448;83213 34373;83258 34365 32;83220 34350 1;83175 34373;83168 34298;83168 34253 1;83145 34140;83108 34058;83070 33975;81765 33983 18;83625 36870 1;83588 36968;83483 37043;83573 37088 1;83753 37200;83910 37260;84090 37373 1;84180 37440;84315 37455;84398 37373 1;84540 37238;84488 37095;84593 36915 1;84713 36705;84840 36608;85080 36548 1;85275 36510;85463 36540;85538 36345 1;85590 36195;85628 36113;85650 35948 1;85658 35850;85628 35775;85553 35715 1;85477 35670;85425 35670;85343 35685 1;84990 35768;84803 35843;84450 35783 1;84308 35760;84165 35730;84098 35850 1;83873 36233;83783 36435;83625 36840;83625 36870 18;83520 37035 1;83453 37185;83415 37268;83378 37418 1;83348 37515;83430 37643;83528 37628 1;83760 37598;83895 37620;84113 37515 1;84173 37485;84240 37463;84300 37410;83520 37035 18;84367 37365 1;84863 37283;85268 37343;85560 36923 1;85643 36803;85650 36683;85583 36540 1;85538 36473;85463 36473;85387 36473 1;85095 36495;84915 36510;84705 36698 1;84495 36885;84465 37050;84367 37298;84367 37365 18;81278 35955 1;81383 36480;81518 36713;81727 37200 1;81773 37320;81900 37373;82012 37313 1;82253 37193;82365 37118;82598 36960 1;82718 36878;82830 36863;82965 36923 1;83168 37020;83408 37043;83617 37133 1;83640 37148;83595 37215;83648 37035 1;83753 36503;83963 36428;84113 35895 1;84120 35850;84090 35828;84075 35783 1;83963 35580;83880 35385;83648 35385 1;83512 35385;83445 35408;83318 35408 1;83280 35408;83235 35400;83242 35363 1;83280 35168;83295 35055;83242 34860 1;83175 34658;83137 34478;82935 34418 1;82658 34350;82477 34493;82290 34695;81278 35955 18;88395 35685 1;88170 35730;88050 35895;88035 36113 1;87998 36450;87983 36615;87960 36945 1;87945 37103;88012 37193;88125 37290 1;88215 37380;88283 37388;88395 37440;88395 35685 18;88931 37484;89374 37484 32;89374 36689 32;88931 36689 32;88931 37484 18;89900 36396;90252 35946 32;89712 35533 32;89367 35983 32;89900 36396 18;84262 37410 1;84675 37658;84908 37740;85365 37912 1;85477 37957;85613 37928;85650 37808 1;85748 37463;85778 37275;85845 36915 1;85852 36840;85740 36758;85680 36803;85598 36848 33;85590 36870;85575 36900;85560 36923 1;85275 37328;84893 37290;84420 37358 32;84352 37320;84262 37410 18;83617 33983;83738 34103 1;83805 34185;83828 34290;83760 34365 1;83708 34425;83633 34388;83573 34343 1;83468 34275;83363 34305;83258 34365;83220 34350 32;83190 34448 33;83190 34493;83220 34537;83265 34575 1;83355 34673;83528 34793;83423 34860 1;83378 34890;83340 34898;83303 34905 32;83242 34860 33;83288 35040;83280 35145;83250 35303 32;83220 35355 33;83273 35348;83340 35363;83408 35385 32;83445 35400 33;83505 35400;83565 35385;83648 35385 1;83880 35385;83963 35580;84075 35783 32;84098 35850 33;84165 35730;84308 35760;84450 35783 1;84803 35843;84990 35768;85343 35685 1;85425 35670;85477 35670;85553 35715 1;85628 35775;85658 35850;85650 35948 1;85628 36113;85590 36195;85538 36345 1;85523 36383;85508 36405;85492 36428 32;85455 36480 33;85500 36480;85545 36495;85583 36540 1;85613 36623;85628 36690;85620 36758 32;85770 36780 1;85943 36638;86048 36510;86137 36353 32;86288 36075 1;86325 36008;86280 35933;86220 35880 1;85838 35573;85673 35378;85410 34965 1;85343 34868;85485 34733;85605 34748 1;86003 34815;86175 35033;86565 35168 1;86678 35213;86790 35040;86813 34912 1;86835 34770;86730 34635;86850 34537 1;86925 34478;87000 34425;87068 34380;86678 33998;83617 33983 18;88193 33998 1;88185 34058;88178 34118;88163 34193 1;88133 34328;88133 34448;88245 34523 1;88358 34605;88425 34628;88545 34703;88665 33998;88193 33998 18;86303 36000 1;86400 36090;86558 36150;86625 36037 1;86790 35753;86768 35662;86880 35340 1;86918 35228;86783 35220;86625 35152;86565 35108 33;86175 34973;86003 34815;85605 34748 1;85485 34733;85343 34868;85410 34965 1;85673 35378;85838 35573;86220 35880 1;86235 35902;86250 35918;86265 35940 32;86303 36000 18;86498 33998;86933 34455 1;87030 34402;87203 34313;87255 34207;87285 34125 33;87285 34080;87285 34035;87270 33990;86498 33998 18;87210 33998 1;87293 34050;87428 34073;87473 33990;87210 33998 18;87465 34005;87345 34043 32;87285 34043 33;87285 34073;87285 34103;87285 34125 32;87255 34207 1;87218 34283;87165 34313;87105 34335 32;87023 34410 33;86970 34448;86910 34493;86850 34537 1;86730 34635;86835 34770;86813 34912 1;86798 34988;86760 35063;86708 35115 32;86625 35152 33;86783 35220;86918 35228;86880 35340 1;86768 35662;86790 35753;86625 36037 1;86558 36150;86400 36090;86303 36000 32;86288 36075 32;86137 36353 33;86048 36510;85943 36638;85770 36780 33;85793 36810;85845 36870;85845 36915 1;85838 36938;85838 36960;85830 36975 32;85823 37020 33;85770 37320;85733 37500;85650 37808 1;85613 37928;85477 37957;85365 37912 1;84930 37755;84698 37673;84323 37455 32;84240 37455 33;84195 37478;84150 37500;84113 37515 1;84098 37523;84090 37530;84075 37530 32;84023 37553 33;83850 37620;83723 37605;83528 37628 1;83430 37643;83393 37508;83423 37410 1;83445 37313;83468 37253;83498 37178 32;83505 37095 33;83325 37035;83130 37005;82965 36923 1;82920 36908;82890 36900;82852 36893 32;82800 36870 32;82290 36465 33;82193 36510;82125 36360;82088 36263 1;82005 36113;82043 36015;81968 35858 1;81893 35707;81690 35745;81548 35828 1;81330 35963;81218 36015;81015 36158 1;80865 36263;80753 36308;80685 36473 1;80565 36735;80505 36863;80378 37110 1;80273 37305;80205 37440;80003 37508 1;79852 37568;79740 37380;79740 37223 1;79725 36878;79695 36705;79658 36353 1;79635 36203;79545 36128;79410 36060 1;79215 35970;79088 35993;78878 35978 1;78360 35955;78068 35910;77625 35858 32;77550 35858 32;77483 36120 32;76898 38453 32;85230 39015;85650 38378 32;86025 37695 32;86288 37200;87180 37365;88395 37440 33;88283 37388;88215 37380;88125 37290 1;88095 37275;88073 37253;88058 37230 32;88020 37193 33;87975 37125;87945 37050;87960 36945 1;87983 36615;87998 36450;88035 36113 1;88043 35918;88148 35760;88343 35700 32;88433 35662 32;88598 34695 32;88448 34650 33;88380 34613;88320 34582;88245 34523 1;88133 34448;88133 34328;88163 34193 1;88178 34118;88185 34050;88193 33990;87450 33998;87465 34005 18;82245 36488;82800 36900 32;82875 36900 33;82905 36900;82935 36915;82965 36923 1;83115 36998;83295 37035;83460 37080 32;83535 37043 33;83535 36998;83595 36938;83625 36870;83625 36840 1;83783 36435;83873 36233;84098 35850 32;84075 35783 33;83963 35580;83880 35385;83648 35385 1;83573 35385;83520 35393;83468 35400 32;83543 35468 33;83693 35603;83745 35790;83670 35873 1;83602 35955;83453 35940;83318 35858 32;83250 35798 33;83100 35670;83048 35483;83130 35393 1;83145 35370;83175 35355;83213 35348 32;83250 35303 33;83280 35145;83288 35040;83242 34860 32;83175 34838 33;83063 34703;83108 34493;82935 34470 1;82762 34455;82658 34470;82530 34575 1;82395 34688;82275 34725;82230 34890 32;82245 34988 33;82230 35250;82313 35370;82418 35603 1;82500 35805;82583 35902;82583 36113 1;82583 36270;82425 36412;82290 36465;82245 36488 18;69352 34590 1;69608 34628;69758 34748;69998 34635 1;70110 34582;70133 34463;70110 34328 1;70073 34178;69990 34095;69848 34035 1;69750 34005;69690 33975;69600 33998 1;69488 34035;69428 34058;69330 34088;69352 34590 18;69233 37740 1;69285 37710;69345 37673;69413 37635 1;69525 37568;69727 37395;69600 37350;69233 37290;69240 37740;69233 37740 18;69248 36248;69555 36713 32;69975 37373 32;70208 37230 33;70448 37058;70673 36885;70838 36750 1;71655 36075;72367 35460;73395 34530 1;73718 34238;73943 34125;74295 33953;69255 33938;69248 36248 18;82305 36465 33;82470 36375;82583 36248;82583 36113 1;82583 35902;82500 35805;82418 35603 1;82313 35370;82230 35250;82245 34988 1;82245 34965;82230 34935;82215 34912;82253 34823 1;82313 34718;82410 34673;82530 34575 1;82658 34470;82762 34455;82935 34470 1;83108 34493;83063 34703;83175 34838 1;83183 34860;83198 34868;83265 34973 1;83288 35108;83265 35213;83213 35348 1;83175 35355;83145 35370;83130 35393 1;83048 35483;83100 35670;83250 35798;83318 35858 1;83453 35940;83602 35955;83670 35873 1;83745 35790;83693 35603;83543 35468;83468 35400 1;83520 35393;83573 35385;83648 35385 1;83880 35385;83963 35580;84075 35783;84098 35850 33;83873 36233;83783 36435;83625 36840;83625 36870 1;83595 36938;83535 36998;83535 37043;80123 33975;80235 34118 1;80378 33953;80558 33960;80783 33990 1;80977 34027;81000 34200;81135 34343 1;81218 34448;81367 34380;81465 34283 1;81548 34207;81668 34103;81585 34013;81518 33968;80123 33975 18;81893 34373;81608 34095 33;81600 34162;81518 34230;81465 34283 1;81367 34380;81218 34448;81135 34343 1;81000 34200;80977 34027;80783 33990 1;80558 33960;80378 33953;80235 34118 32;80213 34178 33;80137 34298;80137 34530;80250 34598 1;80348 34673;80400 34680;80573 34763 32;80723 34793 1;80865 34815;80985 34777;81135 34777 1;81210 34785;81293 34808;81390 34777 33;81398 34650;81420 34537;81548 34463 1;81630 34425;81727 34380;81810 34373;81893 34373 18;79125 33968 1;79238 34020;79328 34035;79448 34133 1;79545 34230;79718 34260;79800 34140 1;79838 34080;79875 34027;79913 33968;79117 33975;79125 33968 18;81540 33990;81585 34013 1;81608 34043;81615 34065;81608 34095 32;81645 34133 32;81893 34373 32;81938 34388;81855 33975;81540 33983;81540 33990 18;95670 46875 1;95588 46770;95550 46710;95475 46598 1;95438 46568;95400 46545;95363 46553 1;95318 46553;95280 46568;95250 46598 1;95130 46710;95025 46733;94973 46875 1;94943 46943;94935 47003;94935 47048 1;94935 47115;94943 47175;95003 47220 1;95063 47303;95085 47363;95183 47400 1;95288 47460;95378 47430;95498 47370 1;95573 47332;95617 47295;95700 47235 1;95730 47220;95753 47183;95753 47138 1;95760 47108;95745 47070;95738 47018 1;95708 46973;95693 46943;95670 46890;99667 53460;99720 52590 32;99000 52523 32;98977 52650 32;98977 52808 1;98955 52965;98933 53108;98910 53302;98835 53378 32;98933 53460;99667 53460 18;100313 75218 1;100283 74850;100215 74670;100170 74295 1;100080 73658;101325 72360;101813 72060;107265 71753 32;108390 67440;101520 67823;103268 65910;97365 37207;96413 35798;113805 35933;115455 35190;115335 36938;116745 38303;118477 35010;118868 76673 1;118118 75915;117443 75473;117480 74408 1;117503 73643;117818 73238;118387 72713 1;119093 72060;119415 71588;120337 71288;106417 70725 1;106515 70793;106628 70830;106718 70748 1;106868 70620;106710 70433;106620 70253 1;106373 69795;106605 69473;106553 68955 1;106523 68730;106477 68602;106320 68430 1;105998 68108;105840 67950;105540 67605 1;105375 67425;105075 67688;105023 67920 1;104940 68273;104985 68475;105113 68805 1;105285 69278;105383 69503;105608 69945 1;105803 70350;106050 70455;106410 70725;106417 70725 18;108352 67560;108398 67463 32;110212 65933 32;110265 65843 1;110183 65783;110160 65730;110078 65670 1;110025 65640;109973 65602;109935 65640 1;109733 65828;109628 65918;109433 66098 1;108975 66525;108683 66653;108143 66945 1;108015 67020;107917 67170;108015 67275 1;108105 67380;108165 67418;108270 67508;108352 67560 18;99090 70635 1;99780 70628;100148 70598;100815 70380 1;100973 70328;101063 70238;101108 70065 1;101243 69525;101438 69262;101445 68700 1;101445 68408;101363 68250;101205 67995 1;101123 67875;101070 67815;101063 67665 1;101055 67575;100792 67553;100830 67635 1;100898 67830;100883 67943;100958 68130 1;101025 68318;101137 68445;101040 68610 1;100883 68873;100800 69038;100530 69173 1;100238 69323;100058 69345;99743 69330 1;99450 69323;99300 69315;99015 69293;99090 70635 18;98880 67477 1;99255 67553;99578 67658;99848 67373 1;100042 67163;100155 67073;100358 66863 1;100455 66758;100688 66810;100718 66953 1;100770 67215;100718 67365;100815 67605 1;100837 67688;100980 67680;101025 67605 1;101153 67403;101355 67178;101565 67313 1;101843 67508;102053 67605;102383 67515 1;102608 67455;102743 67313;102765 67073 1;102788 66803;102727 66630;102555 66413 1;102405 66240;102405 66090;102420 65858 1;102428 65625;102578 65453;102818 65415 1;103268 65363;103665 65340;103920 65723 1;104093 66000;104250 66120;104310 66435 1;104348 66660;104438 66915;104663 66878 1;104880 66848;105030 66720;105075 66495 1;105120 66210;105352 65985;105645 66030 1;106012 66098;106410 66120;106553 65768 1;106703 65393;106725 64957;106373 64762 1;105262 64133;104670 63608;103613 62970 1;103350 62813;103110 62828;103178 62528 1;103365 61695;103395 61740;103590 60900 1;103605 60832;103568 60750;103500 60750 1;103260 60750;103148 60690;102915 60690 1;102840 60690;102795 60735;102773 60795 1;102637 61148;102547 61418;102195 61515 1;100808 61912;100163 62242;98775 62603 1;98573 62655;98348 62662;98288 62468 1;97995 61515;97800 61170;97305 60720 1;97245 60668;97173 60451;97098 60451 1;96896 60458;96861 60334;96831 60521 1;96741 60994;96870 61043;97073 61470 1;97395 62175;97417 62595;97477 63367;97568 63383 33;97703 63360;97845 63375;98010 63427 1;98153 63495;98205 63600;98265 63742 32;98265 63795 1;98355 64095;98385 64245;98490 64537 1;98558 64755;98498 64973;98303 65063 1;98235 65093;98205 65160;98235 65220 1;98422 65685;98580 65887;98783 66345;98880 67477 18;102893 60750;100808 60826 32;98828 60262 32;97425 60255 32;98212 62775 32;98633 62887 32;102390 61733 32;102855 61020;102893 60750 18;98903 67500 1;99225 67553;99428 67620;99727 67477 1;99915 67395;100005 67260;100028 67043 1;100080 66518;99900 66255;99818 65723 1;99705 65033;99608 64635;99150 64095 1;98940 63863;98715 63795;98408 63832 1;98115 63878;97958 63855;97688 63960;97733 64117 32;98828 66390;98850 67117 32;98903 67500 18;104865 66503;108323 67425 32;109028 64950 32;105900 62873 32;106433 61260 32;105150 61373 32;104633 61207 32;103500 60795 32;102690 63427 32;104917 64852;104865 66503 18;105150 66270 1;105120 66413;105083 66593;105225 66615 1;106448 66878;107047 67065;108248 67418 1;108300 67440;108360 67410;108383 67350 1;108615 66435;108720 65977;109005 65070 1;109028 64995;109028 64920;108960 64867 1;107790 64088;107235 63653;106020 62955 1;105953 62925;105885 62873;105915 62798 1;106095 62280;106163 62010;106387 61500 1;106417 61418;106305 61358;106215 61350 1;105780 61335;105555 61433;105128 61350 1;104925 61320;104820 61298;104633 61223 1;104175 61065;103995 60840;103523 60773 1;103440 60765;103350 60765;103343 60840 1;103200 61658;103283 61485;103110 62287 1;103020 62677;103403 62903;103748 63105 1;104318 63457;104738 63720;105420 64155 1;105637 64290;105637 64793;105547 65033 1;105352 65520;105300 65775;105150 66270 18;90503 50235;92340 50512;103223 53100 1;102600 53100;102292 53123;101678 53175;101633 53175 33;101633 53205;101625 53235;101625 53265 1;101528 53707;101445 53963;101303 54293 32;101265 54323 1;102248 54240;102735 54165;103710 53992;103223 53100 18;113940 41393;113933 41850 32;114735 41850 32;114743 41400 32;113940 41393 18;118080 37358;116430 41678;116512 41618 32;118500 40335 32;118462 39060 32;118433 38865 1;118028 38633;117803 38438;117667 37995 1;117375 37073;117540 36480;117922 35588;117983 35513 33;117818 35332;117630 35213;117375 35040 1;117105 34875;116903 34838;116655 34755 32;116385 34770 33;115643 35573;115403 36008;114825 36930 1;114623 37253;114547 37613;114533 37995 32;114533 38183 32;114585 38393 1;114968 38385;115148 38543;115493 38723 1;116055 39030;116430 39390;116430 40027 1;116422 40695;116363 41018;116318 41678;116430 41678 18;114727 37230 1;114480 37200;114337 37253;114120 37358 1;113775 37530;113783 37853;113745 38220 1;113738 38280;113805 38287;113865 38280 1;114105 38273;114225 38348;114473 38370;114727 37230 18;115943 35348 1;115268 35348;114930 35565;114352 35895 1;114210 35978;114233 36150;114308 36285 1;114473 36600;114570 36750;114788 37027;115943 35348 18;111968 34073;112058 34148 1;112440 34388;112658 34455;113063 34665 1;113167 34725;113363 34703;113363 34575 1;113363 34395;113378 34215;113318 34073;111968 34073 18;124545 37508;122010 38648 32;118598 37140 32;118508 40358 32;116333 41738;116265 42375;115868 42353 32;115837 41738 32;114420 40470 32;114075 38340 32;109523 38348 32;109448 43155 32;112613 44033 32;119220 43943 32;124530 43695;124553 37508;124545 37508 18;118823 34080 1;118920 34230;119003 34298;119153 34410 1;119265 34508;119445 34485;119528 34350 1;119587 34245;119640 34170;119685 34088;118815 34095;118823 34080 18;120653 34103 1;120750 34193;120848 34148;120953 34095;120667 34103;120653 34103 18;123465 34110 1;123585 34170;123712 34253;123848 34350 1;123990 34485;124238 34568;124433 34500 1;124477 34485;124523 34478;124560 34470;124568 34110 32;123465 34110 18;119288 35280;119813 34095;114990 34073 1;115417 34238;115875 34418;116415 34650 1;116580 34733;116723 34777;116858 34815 32;116903 34658 1;117045 34433;117158 34253;117262 34080;114990 34088;114990 34073 18;97598 39953 32;99398 40185 1;99653 40223;99893 40245;100118 40275 32;100193 40162 33;99727 39803;99480 39630;98970 39330 1;98565 39098;98303 38948;98085 38595 32;98003 38483 1;97875 39045;97725 39308;97508 39832;97598 39953 50;96098 36323;96158 36930 32;97223 36323 33;97065 35783;96975 35250;96998 34605 32;96188 34793;96098 36323 18;97028 34027 1;96795 35790;97380 36728;97988 38415 1;98227 38895;98505 39060;98970 39330 1;99480 39630;99727 39803;100193 40162;102675 40402;102750 40733;103163 40748;106050 40763;106500 40740;109470 40553;109530 38370;112365 38235 1;112245 37103;112448 36510;112808 35423 1;112845 35295;112792 35175;112672 35115 1;111998 34815;111630 34703;111000 34320 1;110843 34230;110700 34148;110565 34065;97020 34027;97028 34027 18;107258 40433 1;107512 40260;107640 40148;107970 40148 1;108255 40148;108473 40207;108645 40440;107258 40433 18;96765 34020 1;96637 35100;96743 36075;97140 37268 1;97455 38243;97665 38655;98348 39270;88755 34005;88628 34755 32;88538 35287;88508 36630 32;88463 39450 32;95850 39795 32;96165 39255;95460 37560;95438 36923 32;95400 35513;95595 34020;88755 34005 18;117540 74992 1;117637 74873;117533 74393;117630 74265 1;119033 72435;120172 72390;122137 71633 1;123060 71288;123705 71033;124448 70613;120113 71183 1;121343 70762;122333 71168;123225 70193;108510 40305 33;108360 40185;108188 40148;107970 40148 1;107715 40148;107580 40215;107415 40328;96930 44738 1;97740 44655;98258 44745;99165 44655 1;100215 44550;100755 44483;101805 44595 1;102810 44715;103320 44865;104325 44790 1;105248 44745;105727 44670;106590 44310 1;107595 43890;108180 43875;109245 43575 1;110227 43313;110775 43402;111750 43073 1;112868 42705;113445 42563;114570 42135 1;115440 41805;115890 41610;116828 41535 1;118028 41430;118620 41190;119828 41190 1;120885 41190;121417 40823;122310 40230 1;122708 39975;122940 39803;123165 39375 1;123375 38985;123337 38460;122925 38273 1;122288 37995;121980 37815;121305 37613 1;120915 37500;120727 37260;120630 36870 1;120435 36210;120450 35850;120210 35213 1;120128 35010;120038 34853;119933 34710;90105 44213 1;90345 44145;90593 44055;90885 43935 1;91688 43605;92025 43260;92887 43095 1;93727 42930;94170 42983;95025 42953 1;96578 42915;97358 42953;98910 42810 1;100350 42690;101085 42623;102510 42293 1;103515 42060;104010 41790;105045 41730 1;106665 41655;107475 41655;109110 41550 1;109898 41513;110205 41085;110925 40733 1;111765 40335;112320 40313;113047 39713 1;113310 39503;113408 39315;113468 38970 1;113618 38055;113468 37523;113850 36652 1;114158 35940;114345 35580;114870 34995 1;114915 34935;114990 34943;115065 34890 1;115245 34770;115050 34380;114825 34395 1;114345 34425;114098 34380;113625 34350 1;113265 34335;113033 34230;112800 34073;92753 44152 1;93060 44078;93383 44033;93810 44010 1;94598 43995;94988 43853;95790 43853 1;97515 43853;98385 44010;100125 43995 1;101400 43980;102000 43575;103260 43343 1;104505 43125;105105 42825;106380 42743 1;107648 42675;108300 42900;109575 42743 1;110160 42675;110408 42450;110977 42263 1;111675 42045;112140 42210;112778 41820 1;113288 41513;113528 41325;113977 40905 1;114435 40485;114908 40635;115538 40703 1;116348 40800;116768 40853;117578 40703 1;118230 40582;118635 40260;118860 39623 1;119145 38745;119205 38273;119378 37343 1;119475 36743;119610 36285;119205 35813 1;119137 35745;119070 35678;119010 35618;83528 41888 1;83828 41603;84270 41430;84727 41152 1;85380 40763;85620 40425;86295 40065 1;87248 39570;87900 39773;88980 39705 1;90458 39623;91215 39713;92700 39465 1;94005 39240;94643 39218;95820 38588 1;96518 38228;95715 37493;95753 36698 1;95798 35662;95760 35513;95865 34545 1;95887 34328;95903 34155;95910 34020;81375 40148 1;81495 40027;81630 39893;81788 39750 1;82800 38820;83438 38475;84690 37875 1;85800 37343;86445 37170;87390 36353 1;88155 35693;88875 35332;88905 34313 1;88905 34200;88898 34095;88890 33998;76305 38633 1;76508 38363;76785 38123;77108 37815 1;77760 37185;78225 37005;78810 36293 1;79320 35662;79575 35213;79568 34395 1;79560 34245;79553 34103;79538 33968;103898 66593 1;104055 66788;104078 66818;104295 67065 1;104685 67545;105120 67605;105735 67620 1;106560 67665;106935 67283;107655 66863 1;108285 66495;108630 66195;109365 66195 1;110400 66195;110865 66660;111765 67170 1;112350 67515;112920 68003;113408 67530 1;113925 67043;113828 66443;113648 65730 1;113325 64590;112875 64110;112208 63135 1;111375 61943;110340 62025;109065 61313 1;107520 60465;106650 60165;105330 58995 1;105053 58762;104805 58530;104542 58328;69173 56070 1;69390 56018;69623 55973;69908 55935 1;70538 55860;70845 55680;71490 55710 1;72120 55755;72420 55920;73050 56070 1;73830 56273;74175 56490;74925 56790 1;75870 57180;76545 57953;76305 58935 1;76058 59955;75885 60443;75645 61455 1;75458 62220;75518 62685;75810 63412 1;75960 63802;75990 64125;76365 64290 1;76995 64590;77355 64673;78045 64830 1;78735 65010;79230 65040;79665 65610 1;79958 66000;80160 66233;80625 66352 1;81030 66465;81225 66585;81645 66555 1;82238 66525;82568 66330;82988 65895 1;83460 65393;83918 65363;84608 65310 1;85005 65295;85215 65190;85628 65213 1;86205 65250;86475 65423;87045 65550 1;87810 65745;88215 65805;89010 65775 1;90120 65745;90668 65543;91770 65310 1;92887 65085;93518 65175;94590 64733 1;95280 64455;95730 64530;96345 64110 1;96908 63735;97221 63426;97596 62849 1;98106 62046;98370 61662;98865 60845 1;99255 60207;98985 59393;98408 58912 1;97665 58320;97200 58162;96390 57675 1;95475 57143;95115 56730;94185 56250 1;93135 55733;92550 55590;91568 54953 1;90795 54465;90405 54203;89730 53595 1;88770 52740;88148 52485;87270 51555 1;86730 50992;86580 50625;86145 49973 1;85755 49395;85530 49110;85028 48630 1;84308 47963;83970 47565;83565 46673 1;83198 45885;83190 45390;83190 44513 1;83190 43838;83078 43470;83123 42848;88515 77033 1;88898 77250;89198 77430;89730 77430 1;90240 77445;90555 77235;90870 76815 1;91148 76433;91440 76253;91448 75773 1;91448 75555;91538 75443;91530 75210 1;91500 74775;91245 74580;91290 74130 1;91328 73590;91358 73305;91605 72810 1;92145 71745;92708 71123;93885 70830 1;94380 70710;94658 70905;95130 71093 1;95438 71220;95610 71340;95948 71310 1;96465 71280;96795 71153;97125 70733 1;97800 69885;98018 69360;98625 68453 1;98835 68130;98940 67950;99165 67635 1;99308 67440;99608 67515;99765 67695 1;100215 68213;100575 68333;101085 68790 1;101715 69383;102000 69742;102705 70230 1;103297 70650;103635 70815;104348 70995 1;105225 71220;105705 71333;106628 71250 1;107227 71205;107490 70913;107985 70553 1;108547 70155;108908 69923;109605 69930 1;110445 69953;110805 70425;111428 70995 1;111945 71483;112208 71730;112605 72315 1;113070 72990;113490 73290;114285 73470 1;114968 73635;115320 73755;116025 73755 1;116580 73762;117113 73583;117653 73433;92258 51225 1;92183 51188;92100 51143;92025 51090 1;91867 51015;91748 50933;91635 50850;90975 49973 1;90623 49343;90255 49080;89625 48675 1;88635 48052;88208 47640;87308 46890 1;86565 46298;86063 45863;85845 45037 1;85778 44707;85740 44535;85740 44190;115725 36315 1;115943 35828;116198 35543;116715 35543 1;117405 35565;117735 36120;118065 36735 1;118102 36818;118140 36893;118178 36968;118178 35055 1;117960 34928;117735 34793;117488 34590 1;117233 34410;117045 34238;116865 34080;86858 68370;87218 68723 32;86723 69218 32;87023 69503 1;87435 69518;87720 69540;88095 69270 1;88125 69255;88117 69203;88163 69203 1;88373 69218;88455 69330;88658 69405;89250 68325 1;88575 68325;88238 68250;87570 68250 1;87525 68250;87473 68220;87473 68258 1;87458 68340;87413 68393;87338 68393 1;87188 68408;87120 68393;86977 68385 1;86933 68385;86887 68378;86858 68370 18;102165 68318 1;102450 68700;102720 68940;103208 69270 1;103837 69720;104220 69915;104985 70073 1;105765 70245;106230 70343;106988 70073 1;108030 69705;108450 69083;109568 69030 1;110685 68992;111285 69435;112148 70155 1;112958 70845;113160 71453;114090 71970 1;114727 72345;115125 72533;115868 72473 1;116917 72405;117727 72352;118328 71475 1;118845 70703;119258 70425;119970 69795 1;120660 69180;121058 68925;121710 68250 1;122205 67740;122235 67260;122265 66533 1;122295 65475;122070 64823;121365 64012 1;120818 63390;120578 63052;120008 62453 1;119400 61845;118928 61710;118365 61050 1;117848 60465;117525 60233;117068 59595 1;116340 58605;115808 58230;114825 57495 1;113738 56693;112995 56610;111825 55935 1;110310 55065;109417 54810;108030 53753 1;107595 53445;107438 53190;106965 52950 1;105788 52373;105398 51465;104085 51375 1;103238 51323;102825 51060;102090 50655 1;100890 50010;100358 49500;99045 49155 1;97898 48855;97350 48533;96428 47790 1;96158 47588;95948 47423;95730 47243;98520 45975 1;98355 45945;98167 45915;97973 45885 1;97620 45848;97425 45848;97095 45960 1;96563 46148;96323 46283;95798 46463 1;95475 46575;95303 46598;94973 46582 1;93908 46537;93375 46508;92318 46388;101768 46545 1;101655 46478;101633 46380;101618 46320;85950 41993 1;85808 41948;85665 41902;85470 41850 1;84960 41730;84713 41603;84293 41295 1;83963 41070;83790 40973;83468 40740;85913 42752;86526 42070 1;87306 41425;87727 41280;88785 41332 1;90090 41415;90758 41475;92048 41250 1;94035 40920;95018 40605;97050 40455 1;99390 40290;100575 40590;102930 40433 1;104550 40335;105360 39990;106808 39233 1;108165 38520;109005 38303;110047 37155 1;110865 36248;110880 35123;110393 34065;94943 47078 1;94410 47258;94035 47318;93750 47790 1;93645 47963;93653 48165;93810 48278 1;94005 48435;94260 48488;94433 48300 1;94762 47940;95033 47835;95295 47408;94943 47078 18;95010 46673 1;94538 46290;94065 45930;93405 45473 1;93165 45323;92970 45188;92775 45082;73852 57473;70102 55927 1;70073 56040;70193 56100;70305 56130 1;70425 56175;70583 56198;70620 56070 1;70688 55793;70718 55658;70793 55373 1;70823 55253;70725 55155;70613 55103 1;70477 55050;70335 55125;70283 55253;70102 55927 18;69150 64508;69158 64500 32;69150 64508 18;85298 38888 1;86010 37688;86498 36900;86992 35588;86303 36000 1;86400 36090;86558 36150;86625 36037 1;86790 35753;86768 35662;86880 35340 1;86918 35228;86783 35220;86625 35152;86535 35145 33;86145 35010;86003 34815;85605 34748 1;85485 34733;85343 34868;85410 34965 1;85673 35378;85838 35573;86220 35880 1;86235 35902;86250 35918;86265 35940 32;86303 36000 18;86895 39652 1;87240 39953;87548 39893;88005 39938 1;88185 39960;88440 40027;88463 39840 1;88500 39435;88463 39248;88455 38820 1;88455 38738;88500 38625;88418 38603 1;87975 38505;87742 38505;87300 38468 1;86805 38430;86760 39045;86663 39525;86895 39652 18;97794 60918;107123 51255 1;107633 51165;107880 51023;108308 50715 1;109058 50183;109538 50048;110220 49418 1;110340 49305;110355 49200;110393 49028;110955 50512 1;110738 50543;110648 50648;110475 50775 1;109808 51270;109470 51503;108765 51923 1;108518 52073;108488 52065;108248 52223;108630 50258 1;108420 50205;108188 50160;107925 50130 1;106935 50040;106417 50115;105488 49815 1;104490 49515;103995 49320;103050 48915 1;101955 48465;101655 47700;100538 47310 1;100425 47273;100253 47543;100058 47453 1;99878 47370;99953 47168;99840 47085 1;99428 46823;99053 46650;98663 46440 1;98505 46365;98370 46335;98243 46448 1;98100 46582;98033 46755;97845 46718 1;97650 46688;97575 46553;97500 46365 1;97455 46283;97462 46260;97395 46193;104393 52957 1;105540 52943;106178 53025;107250 52590;97462 60128 1;97493 59505;97493 59168;97508 58545 1;97508 58223;97643 58088;97718 57765 1;97950 56693;98145 56100;97913 55020;91463 56378;94425 57052 1;94568 57173;94545 57203;94733 57225 1;95025 57270;95220 57233;95468 57052 1;96413 56355;96690 55710;97118 54608 1;97178 54457;96840 54457;96705 54540 1;96195 54855;95963 55088;95385 55215 1;94920 55320;94845 55710;94538 56055 1;94223 56408;94223 56633;94425 57052 18;96465 53850 1;96428 53393;96555 53137;96398 52703 1;96352 52598;96233 52598;96120 52613 1;95835 52650;95700 52688;95423 52718 1;95265 52740;95137 52808;95123 52957 1;95070 53445;95183 53693;95190 54173 1;95190 54367;95108 54683;95295 54630 1;95835 54495;96480 54473;96488 53910;96465 53850 18;101031 60459 1;101358 60278;100718 59408;100170 59302 1;99075 59108;98535 58973;97440 58875;97493 59190 33;97485 59483;97477 59760;97462 60128 32;97635 60225 33;97650 60225;97665 60225;97688 60225 1;98685 60262;99060 60270;100178 60495 1;100275 60518;100379 60350;100469 60365 32;101031 60459 18;82598 44520 1;83033 44588;83438 44287;83505 43860 1;83573 43433;83663 43433;82838 42960 1;82200 42593;82088 43223;81945 43620 1;81675 44423;82178 44460;82598 44520 18;82950 44490;83617 44925 33;83768 44948;83895 44955;84053 44850 1;84248 44723;84450 44655;84458 44415 1;84458 44183;84315 44078;84143 43920 1;83903 43725;83715 43590;83520 43463 32;83535 43650 32;83145 44490;82950 44490 18;79725 47610 1;80183 47152;80415 46912;80895 46463 1;81195 46185;81383 46043;81540 45660 1;81750 45143;81915 44895;82020 44340;73358 41760 1;73140 41332;73133 40980;72900 40553 1;72803 40388;72630 40748;72623 40935 1;72608 41138;72645 41243;72637 41438 1;72623 41662;72765 41835;72623 42000 1;72038 42675;71708 42983;71145 43665 1;71040 43793;70958 43890;70800 43883 1;70650 43883;70575 43860;70433 43838 1;70298 43830;70268 43980;70238 44100 1;70178 44303;70020 44363;69825 44408 1;69653 44453;69548 44475;69435 44603 1;69180 44888;69420 44498;69458 44865;69765 45240;70260 45585 32;70823 45930;73358 41760 18;69233 40185 1;69360 39540;69548 39053;69758 38250;69225 38925 1;69495 38993;69750 39060;70110 39165 1;70253 39218;70403 39120;70433 38970 1;70477 38738;70515 38625;70538 38385;69233 38228;69233 38933;69225 38925 18;69210 45143 1;69285 45188;69367 45240;69458 45293;69413 45075 1;69443 44933;69413 44850;69367 44707 1;69323 44588;69270 44468;69210 44348;69218 45143;69210 45143 18;69240 37388 1;69360 37402;69473 37418;69637 37425 1;69803 37448;70065 37402;70012 37245 1;69938 37050;69855 36960;69758 36773 1;69698 36683;69683 36630;69645 36525 1;69600 36443;69668 36360;69758 36315 1;69878 36263;69938 36225;70073 36173 1;70170 36143;70193 36045;70185 35933 1;70163 35723;70140 35610;70140 35393 1;70133 35295;70088 35213;69990 35190 1;69765 35160;69668 35085;69450 35040 1;69345 35025;69255 34898;69330 34823 1;69398 34755;69398 34680;69495 34650 1;69518 34643;69480 34613;69473 34582 1;69413 34433;69405 34343;69360 34178 1;69345 34148;69360 34110;69330 34088;69240 34058;69240 37395;69240 37388 18;69248 34050;69330 34088 33;69428 34058;69488 34035;69600 33998 1;69690 33975;69750 34005;69848 34035 1;69990 34095;70073 34178;70110 34328 1;70117 34380;70117 34425;70110 34463 33;70102 34537;70065 34605;69998 34635 1;69795 34733;69660 34665;69495 34650 33;69398 34680;69398 34755;69330 34823 1;69255 34898;69345 35025;69450 35040 1;69668 35085;69765 35160;69990 35190 1;70088 35213;70133 35295;70140 35393 1;70140 35610;70163 35723;70185 35933 1;70193 36045;70170 36143;70073 36173 1;69938 36225;69878 36263;69758 36315 1;69668 36360;69600 36443;69645 36525 1;69683 36630;69698 36683;69758 36773 1;69818 36900;69878 36983;69930 37080;72540 56887 1;72855 56985;73020 56820;73050 56558 1;73050 56363;72953 56048;72637 55950 33;72330 55860;72083 55613;72053 56295 1;72045 56820;71985 56768;72540 56887 18;72833 60473 1;72473 60255;72008 60090;72143 59693 1;72300 59205;72308 58935;72293 58418 1;72270 57758;72255 57375;72233 56730;73980 59153 1;73358 58155;73125 57855;72773 56858;72360 55950 1;72360 55373;72338 55080;72360 54495;87585 73350 1;87675 73020;87818 72600;88148 72698 1;88725 72878;89078 72900;89528 73305 1;89850 73605;89940 73890;89948 74325 1;89948 74805;89970 75135;89648 75473 1;89348 75780;88965 75645;88590 75450 1;88065 75188;87923 74865;87563 74400 1;87308 74085;87465 73808;87585 73350 18;87262 33998;87330 34043 33;87390 34050;87443 34043;87473 33990;87255 33998;87262 33998 18;98565 54585 1;98880 54608;99008 54690;99233 54623 1;99360 54585;99413 54548;99540 54480 1;99600 54450;99608 54420;99615 54345 1;99630 53978;99660 53933;99667 53558 1;99667 53498;99667 53415;99608 53415 1;99315 53415;99128 53393;98895 53385 1;98813 53873;98738 54105;98565 54585 18;70523 46298 1;69863 46035;69795 45443;69210 45082;96839 27067;Forest map sample123255 78068;100740 78000;86288 77955;86602 76852;88110 77108 32;89977 76500 32;90030 73163 32;88913 72428 32;87518 72195 32;89100 68573 32;90375 66968 32;92318 65775 32;97658 64043 32;98828 66338 32;99015 70133 32;99420 72615 32;99830 75218;100312 75150;100140 74078 32;101100 72630 32;101790 72075 32;107190 71760 32;108248 67448 32;108922 64867 32;106598 63195 32;107655 61920 32;111960 62662 32;111960 63435 32;112493 63525 32;112815 62798 32;116250 63278 32;116625 63810 32;116685 64575 32;117608 64537 32;118470 64845 32;120735 65085 32;121703 65018 32;121748 65505 32;122558 65415 32;122753 64927 32;124455 64477;124462 64477;124440 73020;124433 75435;124111 77128;124110 77273 32;123810 77820 32;123255 78068 18;121553 59528;121439 58455;116653 56713;117190 57143;76454 69284 1;76718 68677;76558 67267;77219 67267 1;77998 67267;78614 67769;79287 68161 1;79838 68483;80015 68692;79983 69329 1;79944 70111;79815 70424;79400 71088 1;79109 71553;78866 71605;78394 71326 1;77756 70949;77405 70721;76734 70407 1;76325 70215;76274 69698;76454 69284 18;77063 67349 1;76453 67626;75900 67627;75582 68217 1;75244 68844;74745 69296;75021 69953 1;75367 70774;75898 71195;76756 71433 1;77650 71681;78202 71510;79130 71510;77063 67349 18;82742 72759 1;82742 73189;83015 74001;83319 73697 1;83634 73382;83828 73182;83969 72759 1;84262 71880;83434 70554;84205 70040 1;84646 69746;85256 68794;84782 68557 1;84017 68174;83147 68721;82922 69546 1;82591 70758;82742 71502;82742 72759 18;105741 43279;105210 46148 32;103665 45893 32;102345 45045 32;97583 44123 32;92226 43370 32;89579 43106;88851 42674 32;88282 41889 32;88302 41376;89016 40811;89808 40565;92475 40692 32;97361 41391 32;97728 41725 32;101055 42329 32;105741 43279 18;115695 62535 32;109928 61552 32;109860 60953 32;109373 60953 32;109320 61425 32;108135 61223;109253 59775;109823 56783 32;111727 56595 32;111330 53880 32;113468 53595 32;115485 48720 32;118740 48135 32;118710 47550 32;121255 47315;121230 46298;124515 46223;124523 46223;124500 53093;123450 52935 32;121650 53093 32;121613 52867 32;121387 52748 32;121364 51785;120337 51300 32;120278 50835 32;119025 50430 32;117915 50453 32;117608 50100 32;116873 50168 32;116925 51180 32;117585 51600 32;118268 51563 32;118598 51802 32;119370 51802 32;119723 51518 32;120908 52148 32;120893 53332 32;119422 53820 32;118193 54563 32;117128 54653 32;117128 55260 32;116828 55545 32;115005 55755 32;115087 56145 32;115433 56115 32;115575 57052 32;114968 58635 32;113145 58860 32;113198 59213 32;114908 59025 32;115087 60465 32;114292 60608 32;114345 61095 32;115110 61005 32;115695 62535 50;69135 68858 1;71648 70628;73065 71580;75713 73440 1;77543 74738;78413 75458;80175 76845 1;80723 77288;81060 77535;81510 77940;73898 39547;73831 57316 32;86485 68962 32;95909 51662 32;107957 61624;66336 59806;194054 71555;2103860 48507;3 diff --git a/examples/overprinting.omap b/examples/overprinting.omap index 3a2dbddac..59fc8298b 100644 --- a/examples/overprinting.omap +++ b/examples/overprinting.omap @@ -7,7 +7,7 @@ given without the dot.A solid line indicates that the boundary is marked continuously (tapes, etc.) on the ground.A dashed line indicates intermittent marking on the ground.An area presenting danger to the competitor is shown with cross-hatched diagonal lines.A route which is out-of-bounds is shown with crosses.1061 -1061;-1061 1061;1061 1061;-1061 -1061;The location of a first aid post.-1500 0;1500 0;0 -1500;0 1500;The location of a refreshment point which is not at a control.-1340 -1395;-820 1380;1340 -1395;820 1380;0 -1770 1;600 -1770;1200 -1620;1340 -1395 1;1200 -1170;600 -1020;0 -1020 1;-600 -1020;-1200 -1170;-1340 -1395 1;-1200 -1620;-600 -1770;0 -1770;-820 1380 1;-680 1680;680 1680;820 1380;This symbol provides a simple and quick way to make training courses. +- no line indicates no marking on the ground.A solid line indicates that the boundary is marked continuously (tapes, etc.) on the ground.A dashed line indicates intermittent marking on the ground.An area presenting danger to the competitor is shown with cross-hatched diagonal lines.A route which is out-of-bounds is shown with crosses.1061 -1061;-1061 1061;1061 1061;-1061 -1061;The location of a first aid post.-1500 0;1500 0;0 -1500;0 1500;The location of a refreshment point which is not at a control.-1340 -1395;-820 1380;1340 -1395;820 1380;0 -1770 1;600 -1770;1200 -1620;1340 -1395 1;1200 -1170;600 -1020;0 -1020 1;-600 -1020;-1200 -1170;-1340 -1395 1;-1200 -1620;-600 -1770;0 -1770;-820 1380 1;-680 1680;680 1680;820 1380;This symbol provides a simple and quick way to make training courses. The purple line will extend a bit into the finish symbol. This is a shortcoming of this simple approach.3041 0;3541 0;-3021 3500;3041 0;-3021 -3500;-3021 3500 18;-600 0;600 0;0 0;The OpenOrienteering Logo.-12797 -557 1;-12755 -447;-12770 -420;-12873 -420 1;-12953 -420;-12973 -440;-12973 -520 1;-12973 -635;-12838 -663;-12797 -557 18;-933 2063 1;-933 1925;-920 1900;-851 1900 1;-780 1900;-770 1921;-781 2050 1;-789 2154;-814 2203;-863 2213 1;-920 2224;-933 2197;-933 2063;-933 2063 18;-8875 -3860 1;-8922 -3920;-8984 -3968;-9061 -4006 1;-9134 -4045;-9225 -4065;-9337 -4065 1;-9444 -4065;-9535 -4045;-9612 -4006 1;-9688 -3974;-9752 -3927;-9803 -3867 1;-9855 -3807;-9895 -3737;-9925 -3655 1;-9950 -3578;-9970 -3500;-9982 -3418;-8723 -3418 1;-8725 -3500;-8740 -3578;-8768 -3655 1;-8789 -3732;-8824 -3800;-8875 -3860 18;-4230 -3923 1;-4183 -3737;-4160 -3527;-4160 -3296;-4160 -1395;-5113 -1395;-5113 -3182 1;-5113 -3488;-5155 -3707;-5235 -3833 1;-5317 -3961;-5468 -4027;-5690 -4027 1;-5759 -4027;-5830 -4021;-5907 -4013 1;-5983 -4008;-6052 -4004;-6112 -3993;-6112 -1395;-7064 -1395;-7064 -4646 1;-6903 -4693;-6694 -4736;-6438 -4774 1;-6181 -4818;-5913 -4838;-5631 -4838 1;-5347 -4838;-5110 -4800;-4921 -4723 1;-4730 -4652;-4579 -4547;-4467 -4410 1;-4357 -4273;-4277 -4111;-4230 -3923 18;-13524 1118 1;-13605 1126;-13667 1137;-13708 1150;-13708 3722;-14662 3722;-14662 536 1;-14492 476;-14292 420;-14060 369 1;-13827 314;-13565 286;-13280 286 1;-13229 286;-13167 290;-13096 299 1;-13022 303;-12951 312;-12878 325 1;-12806 333;-12733 345;-12660 363 1;-12587 375;-12526 392;-12474 414;-12634 1201 1;-12719 1180;-12819 1158;-12936 1137 1;-13051 1112;-13174 1098;-13306 1098 1;-13366 1098;-13439 1105;-13524 1118 18;-11093 -200 1;-11204 -101;-11336 -52;-11490 -52 1;-11642 -52;-11777 -101;-11893 -200 1;-12004 -303;-12059 -441;-12059 -616 1;-12059 -791;-12004 -927;-11893 -1026 1;-11777 -1128;-11642 -1179;-11490 -1179 1;-11336 -1179;-11204 -1128;-11093 -1026 1;-10978 -927;-10920 -791;-10920 -616 1;-10920 -441;-10978 -303;-11093 -200 18;-11009 3722;-11963 3722;-11963 357;-11009 357;-11009 3722 18;-8649 1053 1;-8755 1053;-8847 1073;-8924 1112 1;-9001 1145;-9065 1192;-9115 1252 1;-9167 1312;-9207 1381;-9237 1464 1;-9264 1539;-9282 1618;-9296 1700;-8034 1700 1;-8039 1618;-8054 1539;-8079 1464 1;-8101 1387;-8137 1318;-8189 1259 1;-8236 1199;-8297 1150;-8374 1112 1;-8445 1073;-8537 1053;-8649 1053 18;-5220 1105 1;-5297 1110;-5365 1115;-5425 1125;-5425 3722;-6378 3722;-6378 472 1;-6217 425;-6007 382;-5751 344 1;-5495 301;-5227 280;-4945 280 1;-4658 280;-4422 318;-4235 395 1;-4042 467;-3890 572;-3781 709 1;-3669 845;-3591 1007;-3544 1195 1;-3497 1381;-3474 1592;-3474 1821;-3474 3722;-4427 3722;-4427 1937 1;-4427 1630;-4467 1411;-4549 1285 1;-4628 1156;-4780 1092;-5002 1092 1;-5070 1092;-5143 1097;-5220 1105 18;-2636 2346;-2636 -481;-1683 -634;-1683 357;-539 357;-539 1150;-1683 1150;-1683 2333 1;-1683 2535;-1648 2694;-1581 2813 1;-1508 2933;-1365 2993;-1151 2993 1;-1050 2993;-945 2984;-838 2966 1;-728 2946;-627 2918;-539 2884;-404 3626 1;-518 3673;-646 3712;-787 3748 1;-928 3780;-1102 3799;-1305 3799 1;-1566 3799;-1781 3764;-1951 3696 1;-2123 3624;-2259 3526;-2361 3402 1;-2463 3274;-2536 3121;-2579 2941 1;-2618 2763;-2636 2565;-2636 2346 18;2142 1464 1;2121 1387;2084 1318;2032 1259 1;1986 1199;1924 1150;1847 1112 1;1776 1073;1685 1053;1572 1053 1;1466 1053;1375 1073;1298 1112 1;1221 1145;1156 1192;1106 1252 1;1054 1312;1014 1381;984 1464 1;958 1539;939 1618;926 1700;2187 1700 1;2183 1618;2168 1539;2142 1464 18;5923 1700 1;5919 1618;5904 1539;5878 1464 1;5856 1387;5821 1318;5769 1259 1;5723 1199;5661 1150;5585 1112 1;5511 1073;5419 1053;5308 1053 1;5201 1053;5110 1073;5033 1112 1;4957 1145;4893 1192;4841 1252 1;4790 1312;4750 1381;4720 1464 1;4695 1539;4675 1618;4663 1700;5923 1700 18;8718 1118 1;8637 1126;8575 1137;8534 1150;8534 3722;7581 3722;7581 536 1;7750 476;7950 420;8182 369 1;8415 314;8677 286;8962 286 1;9013 286;9075 290;9146 299 1;9220 303;9292 312;9365 325 1;9437 333;9510 345;9583 363 1;9655 375;9717 392;9768 414;9608 1201 1;9523 1180;9424 1158;9306 1137 1;9191 1112;9069 1098;8937 1098 1;8877 1098;8804 1105;8718 1118 18;10350 -200 1;10238 -303;10183 -441;10183 -616 1;10183 -791;10238 -927;10350 -1026 1;10465 -1128;10600 -1179;10752 -1179 1;10906 -1179;11038 -1128;11149 -1026 1;11264 -927;11323 -791;11323 -616 1;11323 -441;11264 -303;11149 -200 1;11038 -101;10906 -52;10752 -52 1;10600 -52;10465 -101;10350 -200 18;11233 3722;10279 3722;10279 357;11233 357;11233 3722 18;14726 709 1;14836 845;14916 1007;14963 1195 1;15010 1381;15033 1592;15033 1821;15033 3722;14080 3722;14080 1937 1;14080 1630;14039 1411;13958 1285 1;13876 1156;13725 1092;13504 1092 1;13435 1092;13363 1097;13287 1105 1;13210 1110;13142 1115;13082 1125;13082 3722;12129 3722;12129 472 1;12290 425;12499 382;12756 344 1;13012 301;13280 280;13562 280 1;13847 280;14083 318;14272 395 1;14463 467;14614 572;14726 709 18;-17051 -1307 1;-17299 -1307;-17525 -1349;-17729 -1434 1;-17931 -1521;-18102 -1639;-18247 -1794 1;-18392 -1951;-18505 -2139;-18587 -2355 1;-18669 -2579;-18708 -2820;-18708 -3085 1;-18708 -3350;-18669 -3591;-18587 -3808 1;-18502 -4027;-18387 -4211;-18242 -4365 1;-18092 -4518;-17917 -4638;-17717 -4723 1;-17512 -4808;-17291 -4851;-17051 -4851 1;-16808 -4851;-16586 -4808;-16386 -4723 1;-16182 -4638;-16006 -4518;-15861 -4365 1;-15716 -4211;-15603 -4027;-15523 -3808 1;-15442 -3591;-15401 -3350;-15401 -3085 1;-15401 -2820;-15440 -2579;-15517 -2355 1;-15593 -2139;-15703 -1951;-15848 -1794 1;-15993 -1639;-16168 -1521;-16373 -1434 1;-16574 -1349;-16800 -1307;-17051 -1307 18;-17051 -2126 1;-16834 -2126;-16668 -2210;-16552 -2383 1;-16433 -2557;-16373 -2792;-16373 -3085 1;-16373 -3380;-16433 -3610;-16552 -3777 1;-16668 -3946;-16834 -4034;-17051 -4034 1;-17269 -4034;-17437 -3946;-17557 -3777 1;-17675 -3610;-17736 -3380;-17736 -3085 1;-17736 -2792;-17675 -2557;-17557 -2383 1;-17437 -2210;-17269 -2126;-17051 -2126 18;-14662 -213;-14662 -4646 1;-14576 -4673;-14478 -4697;-14369 -4716 1;-14257 -4743;-14142 -4765;-14022 -4781 1;-13898 -4798;-13776 -4811;-13652 -4819 1;-13524 -4833;-13402 -4838;-13287 -4838 1;-13009 -4838;-12763 -4796;-12544 -4711 1;-12328 -4630;-12144 -4513;-11995 -4358 1;-11846 -4210;-11732 -4027;-11657 -3808 1;-11574 -3591;-11535 -3348;-11535 -3078 1;-11535 -2819;-11566 -2582;-11629 -2368 1;-11694 -2156;-11788 -1972;-11911 -1819 1;-12034 -1666;-12189 -1546;-12373 -1461 1;-12556 -1376;-12765 -1333;-13006 -1333 1;-13137 -1333;-13261 -1346;-13377 -1371 1;-13492 -1395;-13602 -1432;-13708 -1479;-13708 -213;-14662 -213 18;-13184 -2139 1;-12733 -2139;-12506 -2443;-12506 -3054 1;-12506 -3348;-12572 -3582;-12704 -3756 1;-12837 -3936;-13032 -4027;-13293 -4027 1;-13379 -4027;-13457 -4021;-13530 -4013 1;-13602 -4008;-13662 -4004;-13708 -3993;-13708 -2274 1;-13648 -2234;-13572 -2202;-13479 -2177 1;-13381 -2152;-13282 -2139;-13184 -2139 18;-9182 -1307 1;-9485 -1307;-9750 -1352;-9976 -1440 1;-10198 -1530;-10383 -1652;-10533 -1806 1;-10678 -1964;-10787 -2149;-10858 -2362 1;-10926 -2575;-10962 -2807;-10962 -3054 1;-10962 -3352;-10917 -3612;-10827 -3833 1;-10733 -4060;-10611 -4248;-10462 -4396 1;-10314 -4547;-10141 -4660;-9950 -4736 1;-9754 -4813;-9553 -4851;-9349 -4851 1;-8872 -4851;-8494 -4705;-8217 -4410 1;-7939 -4120;-7801 -3692;-7801 -3123 1;-7801 -3069;-7803 -3007;-7808 -2939 1;-7810 -2873;-7816 -2817;-7819 -2766;-9982 -2766 1;-9961 -2569;-9870 -2413;-9707 -2299 1;-9545 -2184;-9327 -2126;-9055 -2126 1;-8881 -2126;-8708 -2141;-8542 -2171 1;-8372 -2205;-8234 -2246;-8127 -2292;-7999 -1517 1;-8051 -1493;-8119 -1468;-8204 -1440 1;-8289 -1416;-8385 -1395;-8492 -1378 1;-8594 -1356;-8706 -1339;-8824 -1326 1;-8944 -1314;-9063 -1307;-9182 -1307 18;-9982 -3418;-8723 -3418 1;-8725 -3500;-8740 -3578;-8768 -3655 1;-8789 -3732;-8824 -3800;-8875 -3860 1;-8922 -3920;-8984 -3968;-9061 -4006 1;-9134 -4045;-9225 -4065;-9337 -4065 1;-9444 -4065;-9535 -4045;-9612 -4006 1;-9688 -3974;-9752 -3927;-9803 -3867 1;-9855 -3807;-9895 -3737;-9925 -3655 1;-9950 -3578;-9970 -3500;-9982 -3418 18;-17051 -2126 1;-17269 -2126;-17437 -2210;-17557 -2383 1;-17675 -2557;-17736 -2792;-17736 -3085 1;-17736 -3380;-17675 -3610;-17557 -3777 1;-17437 -3946;-17269 -4034;-17051 -4034 1;-16834 -4034;-16668 -3946;-16552 -3777 1;-16433 -3610;-16373 -3380;-16373 -3085 1;-16373 -2792;-16433 -2557;-16552 -2383 1;-16668 -2210;-16834 -2126;-17051 -2126 18;-17064 -2593 1;-16944 -2591;-16842 -2808;-16838 -3077 1;-16834 -3347;-16928 -3567;-17049 -3569 1;-17170 -3571;-17271 -3354;-17275 -3084 1;-17280 -2815;-17185 -2595;-17064 -2593 18;-8496 3810 1;-8798 3810;-9062 3765;-9288 3677 1;-9510 3588;-9696 3466;-9845 3312 1;-9990 3154;-10098 2969;-10171 2756 1;-10240 2542;-10273 2311;-10273 2065 1;-10273 1766;-10230 1507;-10140 1285 1;-10045 1058;-9923 870;-9775 722 1;-9625 572;-9455 459;-9264 382 1;-9067 305;-8867 267;-8662 267 1;-8184 267;-7806 414;-7529 709 1;-7252 998;-7113 1426;-7113 1995 1;-7113 2050;-7116 2112;-7119 2180 1;-7124 2245;-7128 2301;-7132 2353;-9296 2353 1;-9273 2550;-9182 2704;-9020 2820 1;-8857 2934;-8640 2993;-8368 2993 1;-8193 2993;-8022 2978;-7855 2948 1;-7684 2912;-7546 2873;-7440 2826;-7311 3601 1;-7363 3626;-7431 3651;-7516 3677 1;-7603 3703;-7697 3724;-7804 3741 1;-7908 3763;-8017 3779;-8137 3793 1;-8257 3804;-8376 3810;-8496 3810 18;-9296 1700;-8034 1700 1;-8039 1618;-8054 1539;-8079 1464 1;-8101 1387;-8137 1318;-8189 1259 1;-8236 1199;-8297 1150;-8374 1112 1;-8445 1073;-8537 1053;-8649 1053 1;-8755 1053;-8847 1073;-8924 1112 1;-9001 1145;-9065 1192;-9115 1252 1;-9167 1312;-9207 1381;-9237 1464 1;-9264 1539;-9282 1618;-9296 1700 18;1726 3810 1;1422 3810;1159 3765;933 3677 1;712 3588;524 3466;376 3312 1;231 3154;123 2969;49 2756 1;-19 2542;-52 2311;-52 2065 1;-52 1766;-9 1507;81 1285 1;177 1058;298 870;446 722 1;596 572;766 459;958 382 1;1154 305;1354 267;1559 267 1;2038 267;2416 414;2692 709 1;2968 998;3109 1426;3109 1995 1;3109 2050;3105 2112;3102 2180 1;3097 2245;3094 2301;3088 2353;926 2353 1;947 2550;1039 2704;1201 2820 1;1364 2934;1581 2993;1854 2993 1;2029 2993;2199 2978;2365 2948 1;2538 2912;2675 2873;2782 2826;2910 3601 1;2859 3626;2790 3651;2705 3677 1;2619 3703;2524 3724;2417 3741 1;2314 3763;2204 3779;2084 3793 1;1965 3804;1846 3810;1726 3810 18;926 1700;2187 1700 1;2183 1618;2168 1539;2142 1464 1;2121 1387;2084 1318;2032 1259 1;1986 1199;1924 1150;1847 1112 1;1776 1073;1685 1053;1572 1053 1;1466 1053;1375 1073;1298 1112 1;1221 1145;1156 1192;1106 1252 1;1054 1312;1014 1381;984 1464 1;958 1539;939 1618;926 1700 18;5463 3810 1;5160 3810;4895 3765;4668 3677 1;4446 3588;4262 3466;4112 3312 1;3967 3154;3858 2969;3787 2756 1;3719 2542;3684 2311;3684 2065 1;3684 1766;3729 1507;3819 1285 1;3911 1058;4033 870;4183 722 1;4332 572;4503 459;4695 382 1;4891 305;5091 267;5297 267 1;5773 267;6151 414;6428 709 1;6706 998;6844 1426;6844 1995 1;6844 2050;6843 2112;6837 2180 1;6834 2245;6829 2301;6826 2353;4663 2353 1;4683 2550;4775 2704;4938 2820 1;5100 2934;5318 2993;5590 2993 1;5765 2993;5936 2978;6103 2948 1;6272 2912;6411 2873;6518 2826;6646 3601 1;6594 3626;6526 3651;6441 3677 1;6356 3703;6259 3724;6152 3741 1;6051 3763;5939 3779;5821 3793 1;5701 3804;5581 3810;5463 3810 18;4663 1700;5923 1700 1;5919 1618;5904 1539;5878 1464 1;5856 1387;5821 1318;5769 1259 1;5723 1199;5661 1150;5585 1112 1;5511 1073;5419 1053;5308 1053 1;5201 1053;5110 1073;5033 1112 1;4957 1145;4893 1192;4841 1252 1;4790 1312;4750 1381;4720 1464 1;4695 1539;4675 1618;4663 1700 18;17092 4924 1;16887 4924;16682 4905;16477 4867 1;16272 4832;16083 4785;15908 4725;16074 3926 1;16224 3986;16379 4032;16543 4067 1;16707 4101;16896 4119;17105 4119 1;17377 4119;17570 4059;17680 3939 1;17796 3819;17854 3666;17854 3479;17854 3357 1;17750 3404;17644 3441;17533 3466 1;17427 3487;17309 3498;17182 3498 1;16717 3498;16361 3361;16113 3087 1;15866 2811;15743 2424;15743 1930 1;15743 1683;15781 1458;15857 1259 1;15934 1053;16044 878;16189 733 1;16339 589;16521 478;16734 402 1;16947 320;17187 280;17457 280 1;17572 280;17689 286;17809 299 1;17931 307;18053 320;18173 337 1;18292 354;18405 375;18512 402 1;18624 422;18722 446;18806 472;18806 3299 1;18806 3849;18665 4257;18385 4522 1;18107 4790;17677 4924;17092 4924 18;17360 2730 1;17459 2730;17550 2718;17636 2691 1;17720 2666;17794 2636;17854 2603;17854 1080 1;17807 1072;17750 1065;17687 1060 1;17623 1052;17548 1047;17464 1047 1;17212 1047;17024 1130;16900 1297 1;16776 1464;16714 1675;16714 1930 1;16714 2463;16930 2730;17360 2730 18;-17051 2993 1;-17269 2993;-17437 2908;-17557 2736 1;-17675 2561;-17736 2326;-17736 2033 1;-17736 1738;-17675 1509;-17557 1342 1;-17437 1171;-17269 1085;-17051 1085 1;-16834 1085;-16668 1171;-16552 1342 1;-16433 1509;-16373 1738;-16373 2033 1;-16373 2326;-16433 2561;-16552 2736 1;-16668 2908;-16834 2993;-17051 2993 18;-17064 2526 1;-16944 2528;-16842 2311;-16838 2042 1;-16834 1772;-16928 1552;-17049 1550 1;-17170 1548;-17271 1765;-17275 2035 1;-17280 2304;-17185 2524;-17064 2526 18;-17051 3810 1;-17299 3810;-17525 3769;-17729 3684 1;-17931 3598;-18102 3479;-18247 3324 1;-18392 3168;-18505 2980;-18587 2763 1;-18669 2540;-18708 2298;-18708 2033 1;-18708 1768;-18669 1526;-18587 1310 1;-18502 1092;-18387 906;-18242 754 1;-18092 600;-17917 480;-17717 395 1;-17512 310;-17291 267;-17051 267 1;-16808 267;-16586 310;-16386 395 1;-16182 480;-16006 600;-15861 754 1;-15716 906;-15603 1092;-15523 1310 1;-15442 1526;-15401 1768;-15401 2033 1;-15401 2298;-15440 2540;-15517 2763 1;-15593 2980;-15703 3168;-15848 3324 1;-15993 3479;-16168 3598;-16373 3684 1;-16574 3769;-16800 3810;-17051 3810 18;-17051 2993 1;-16834 2993;-16668 2908;-16552 2736 1;-16433 2561;-16373 2326;-16373 2033 1;-16373 1738;-16433 1509;-16552 1342 1;-16668 1171;-16834 1085;-17051 1085 1;-17269 1085;-17437 1171;-17557 1342 1;-17675 1509;-17736 1738;-17736 2033 1;-17736 2326;-17675 2561;-17557 2736 1;-17437 2908;-17269 2993;-17051 2993 18;17090 5390 1;16864 5390;16623 5362;16391 5321 1;16389 5320;16389 5320;16387 5320 1;16169 5284;15963 5240;15758 5170 1;15555 5102;15409 4847;15450 4637 1;15450 4635;15450 4634;15450 4632;15538 4221 1;15549 4165;15526 4109;15478 4079 1;15431 4049;15369 4052;15324 4088 1;15245 4152;15138 4191;15033 4191;14080 4191 1;13930 4193;13775 4107;13692 3983 1;13669 3944;13625 3921;13580 3921 1;13534 3921;13492 3944;13466 3983 1;13385 4107;13233 4191;13083 4191;12131 4191 1;12001 4191;11866 4131;11781 4032 1;11755 4004;11719 3987;11680 3987 1;11642 3987;11606 4004;11581 4032 1;11496 4131;11364 4191;11234 4191;10281 4191 1;10048 4193;9815 3957;9815 3724;9815 1796 1;9815 1758;9798 1721;9770 1697 1;9741 1670;9703 1658;9665 1663 1;9608 1670;9553 1668;9498 1655 1;9433 1638;9341 1618;9227 1597 1;9221 1595;9217 1593;9210 1592 1;9161 1582;9142 1582;9157 1584 1;9118 1578;9078 1590;9048 1615 1;9018 1640;9001 1678;9001 1716 1;9001 1716;9001 3724;9001 3724 1;9001 3957;8768 4193;8535 4191;7582 4191 1;7424 4191;7262 4099;7183 3962 1;7162 3926;7125 3900;7082 3894 1;7040 3889;6999 3902;6969 3932 1;6935 3966;6899 3996;6855 4016 1;6768 4059;6679 4092;6574 4124 1;6467 4157;6364 4178;6253 4195 1;6244 4197;6236 4199;6226 4202 1;6107 4227;5991 4240;5870 4254 1;5738 4267;5601 4279;5461 4279 1;5121 4279;4808 4231;4520 4120 1;4514 4118;4506 4114;4498 4110 1;4220 3998;3977 3840;3778 3636 1;3717 3566;3663 3494;3609 3412 1;3571 3361;3503 3344;3445 3371 1;3389 3396;3357 3459;3370 3521 1;3404 3711;3293 3930;3120 4016 1;3034 4060;2945 4092;2837 4124 1;2732 4157;2628 4178;2517 4195 1;2508 4197;2499 4199;2490 4202 1;2372 4227;2256 4240;2134 4254 1;2001 4267;1866 4279;1726 4279 1;1386 4279;1071 4231;785 4120 1;778 4118;771 4114;761 4110 1;562 4029;383 3917;218 3782 1;186 3757;145 3748;105 3757 1;64 3765;32 3793;13 3829 1;-35 3929;-124 4013;-229 4054 1;-362 4109;-512 4164;-678 4204 1;-871 4251;-1073 4266;-1303 4266 1;-1606 4266;-1876 4227;-2127 4126 1;-2355 4031;-2561 3892;-2717 3706 1;-2719 3701;-2721 3699;-2719 3702 1;-2716 3707;-2718 3706;-2721 3700 1;-2724 3694;-2734 3667;-2764 3624 1;-2799 3577;-2859 3558;-2915 3576 1;-2969 3594;-3007 3646;-3006 3704;-3006 3724 1;-3006 3957;-3239 4193;-3473 4191;-4427 4191 1;-4577 4193;-4730 4107;-4814 3983 1;-4838 3944;-4880 3921;-4927 3921 1;-4972 3921;-5013 3944;-5038 3983 1;-5122 4107;-5274 4191;-5421 4191;-6377 4191 1;-6533 4191;-6696 4099;-6777 3962 1;-6796 3926;-6833 3900;-6875 3894 1;-6916 3889;-6958 3902;-6988 3932 1;-7021 3966;-7059 3996;-7101 4016 1;-7101 4017;-7104 4016;-7104 4016 1;-7191 4059;-7278 4092;-7384 4124 1;-7489 4157;-7592 4178;-7704 4195 1;-7714 4197;-7722 4199;-7729 4199 1;-7731 4201;-7733 4202;-7735 4204 1;-7849 4227;-7966 4240;-8088 4254 1;-8221 4267;-8355 4279;-8496 4279 1;-8836 4279;-9151 4231;-9437 4120 1;-9444 4118;-9450 4114;-9461 4110 1;-9737 3998;-9980 3840;-10181 3635 1;-10185 3631;-10185 3628;-10186 3624 1;-10218 3591;-10250 3536;-10300 3470 1;-10333 3425;-10393 3404;-10450 3423 1;-10505 3440;-10541 3493;-10541 3549 1;-10541 3549;-10541 3724;-10541 3724 1;-10541 3957;-10774 4193;-11008 4191;-11961 4191 1;-12194 4193;-12427 3957;-12427 3724;-12427 1796 1;-12427 1758;-12444 1721;-12472 1697 1;-12501 1670;-12539 1658;-12577 1663 1;-12634 1670;-12689 1668;-12744 1655 1;-12809 1638;-12901 1618;-13015 1597 1;-13021 1595;-13026 1593;-13032 1592 1;-13081 1582;-13101 1582;-13086 1584 1;-13124 1578;-13164 1590;-13194 1615 1;-13224 1640;-13240 1678;-13240 1716;-13240 3724 1;-13240 3957;-13474 4193;-13707 4191;-14660 4191 1;-14893 4193;-15126 3957;-15126 3724;-15126 3532 1;-15126 3476;-15164 3423;-15218 3406 1;-15273 3387;-15335 3408;-15368 3455 1;-15420 3526;-15463 3591;-15511 3643 1;-15517 3651;-15517 3652;-15518 3656 1;-15703 3851;-15933 4002;-16189 4110 1;-16458 4224;-16748 4279;-17051 4279 1;-17346 4279;-17629 4225;-17889 4120 1;-17895 4118;-17902 4114;-17909 4112 1;-18160 4005;-18392 3849;-18580 3651 1;-18586 3643;-18587 3641;-18588 3637 1;-18776 3434;-18919 3196;-19017 2931 1;-19017 2931;-19017 2933;-19019 2927 1;-19122 2648;-19176 2350;-19176 2033 1;-19176 1718;-19123 1419;-19019 1142;-19019 1139 1;-18913 875;-18770 642;-18587 446 1;-18407 241;-18054 35;-17897 -33 1;-17894 -33;-17891 -35;-17889 -37 1;-17628 -143;-17344 -200;-17051 -200 1;-16755 -200;-16468 -143;-16206 -33 1;-15946 76;-15707 235;-15518 433 1;-15470 487;-15425 560;-15368 639 1;-15335 685;-15273 705;-15218 687 1;-15164 669;-15126 617;-15126 559;-15126 538 1;-15126 435;-15088 329;-15023 247 1;-14983 198;-14983 129;-15023 80 1;-15088 -1;-15126 -108;-15126 -211;-15126 -1586 1;-15126 -1644;-15164 -1696;-15218 -1714 1;-15273 -1733;-15335 -1712;-15368 -1666 1;-15420 -1594;-15463 -1529;-15506 -1483 1;-15508 -1478;-15511 -1474;-15517 -1465 1;-15701 -1271;-15928 -1115;-16189 -1005 1;-16463 -889;-16753 -841;-17051 -841 1;-17341 -841;-17624 -888;-17889 -995 1;-17895 -997;-17902 -1001;-17909 -1003 1;-18165 -1113;-18394 -1273;-18578 -1463 1;-18582 -1468;-18582 -1470;-18584 -1474 1;-18586 -1476;-18587 -1479;-18588 -1483 1;-18776 -1684;-18919 -1924;-19019 -2192 1;-19122 -2472;-19176 -2770;-19176 -3085 1;-19176 -3401;-19122 -3698;-19019 -3973 1;-18915 -4238;-18774 -4473;-18586 -4675 1;-18582 -4680;-18580 -4682;-18580 -4684 1;-18577 -4686;-18573 -4688;-18572 -4690 1;-18384 -4883;-18152 -5043;-17897 -5151 1;-17894 -5153;-17891 -5154;-17889 -5156 1;-17628 -5263;-17344 -5317;-17051 -5317 1;-16755 -5317;-16468 -5263;-16204 -5150 1;-15943 -5038;-15707 -4885;-15518 -4684 1;-15468 -4631;-15425 -4560;-15368 -4481 1;-15335 -4433;-15273 -4413;-15218 -4431 1;-15164 -4449;-15126 -4502;-15126 -4560 1;-15126 -4560;-15126 -4648;-15126 -4648 1;-15126 -4840;-14978 -5038;-14794 -5093 1;-14694 -5123;-14598 -5144;-14499 -5165 1;-14499 -5165;-14477 -5168;-14452 -5173 1;-14340 -5198;-14217 -5219;-14085 -5240 1;-13922 -5266;-13842 -5266;-13682 -5281 1;-13547 -5294;-13415 -5306;-13286 -5306 1;-12964 -5306;-12660 -5253;-12380 -5145 1;-12373 -5143;-12371 -5143;-12369 -5143 1;-12101 -5041;-11864 -4883;-11665 -4681 1;-11657 -4671;-11653 -4668;-11649 -4665 1;-11536 -4548;-11441 -4412;-11358 -4260 1;-11334 -4218;-11289 -4192;-11242 -4192 1;-11193 -4192;-11148 -4218;-11125 -4260 1;-11028 -4434;-10923 -4593;-10791 -4726 1;-10600 -4917;-10372 -5065;-10128 -5165 1;-10125 -5165;-10124 -5166;-10118 -5168 1;-9872 -5263;-9613 -5317;-9350 -5317 1;-8783 -5317;-8251 -5120;-7882 -4730 1;-7846 -4691;-7812 -4641;-7767 -4581 1;-7733 -4538;-7676 -4519;-7622 -4536 1;-7569 -4553;-7532 -4600;-7529 -4656 1;-7526 -4846;-7376 -5039;-7192 -5093 1;-6999 -5148;-6777 -5186;-6518 -5226 1;-6513 -5227;-6510 -5229;-6505 -5231 1;-6226 -5276;-5933 -5306;-5630 -5306 1;-5305 -5306;-5020 -5259;-4754 -5153 1;-4499 -5054;-4271 -4908;-4106 -4706 1;-3948 -4513;-3839 -4282;-3777 -4034 1;-3719 -3803;-3694 -3557;-3694 -3294;-3694 -1395 1;-3694 -1161;-3927 -927;-4160 -927;-5113 -927 1;-5263 -927;-5419 -1011;-5502 -1136 1;-5525 -1174;-5569 -1198;-5613 -1198 1;-5660 -1198;-5701 -1174;-5727 -1136 1;-5808 -1012;-5960 -927;-6110 -927;-7063 -927 1;-7220 -929;-7380 -1021;-7459 -1158 1;-7479 -1194;-7516 -1219;-7558 -1224 1;-7599 -1231;-7641 -1216;-7671 -1186 1;-7706 -1151;-7744 -1121;-7790 -1100 1;-7898 -1046;-7976 -1023;-8071 -995 1;-8178 -963;-8281 -942;-8392 -924 1;-8400 -923;-8409 -921;-8417 -920 1;-8419 -918;-8419 -916;-8421 -916 1;-8527 -894;-8644 -874;-8775 -861 1;-8917 -846;-9054 -841;-9183 -841 1;-9523 -841;-9837 -888;-10125 -999 1;-10132 -1003;-10138 -1004;-10148 -1010 1;-10205 -1033;-10261 -1066;-10333 -1102 1;-10380 -1126;-10438 -1119;-10478 -1085 1;-10520 -1051;-10537 -996;-10520 -944 1;-10481 -826;-10453 -709;-10453 -616 1;-10453 -441;-10525 -246;-10637 -67 1;-10667 -20;-10665 40;-10633 84 1;-10575 164;-10541 262;-10541 359;-10541 559 1;-10541 617;-10505 669;-10450 687 1;-10393 705;-10333 685;-10300 639 1;-10233 547;-10171 461;-10103 392 1;-9914 202;-9685 53;-9442 -45 1;-9439 -46;-9435 -48;-9433 -50 1;-9432 -50;-9431 -50;-9429 -50 1;-9183 -144;-8927 -200;-8662 -200 1;-8096 -200;-7562 -1;-7194 386;-7194 386 1;-7192 387;-7194 385;-7194 388 1;-7192 392;-7192 389;-7192 390;-7143 453;-7079 538 1;-7046 581;-6988 598;-6935 581 1;-6882 566;-6846 519;-6843 463 1;-6837 273;-6688 79;-6505 25 1;-6313 -30;-6091 -67;-5824 -110 1;-5540 -156;-5246 -186;-4944 -186 1;-4619 -186;-4332 -142;-4066 -35 1;-3813 64;-3584 211;-3419 414 1;-3404 432;-3387 477;-3347 534 1;-3315 585;-3254 609;-3195 590 1;-3139 574;-3101 519;-3103 459 1;-3103 459;-3103 -482;-3103 -482 1;-3103 -693;-2915 -908;-2706 -941;-1753 -1091 1;-1501 -1129;-1215 -886;-1215 -633;-1215 -241 1;-1215 -166;-1155 -108;-1082 -108;-537 -108 1;-323 -106;-109 82;-79 292 1;-70 342;-35 384;11 399 1;60 415;111 402;147 367 1;333 190;549 49;786 -47 1;1037 -144;1294 -200;1559 -200 1;2126 -200;2658 -1;3027 388 1;3144 513;3239 654;3317 805 1;3338 848;3383 875;3432 875 1;3481 876;3526 852;3550 808 1;3642 654;3737 510;3853 392 1;4045 202;4273 53;4521 -47;4521 -47 1;4521 -48;4520 -46;4522 -47 1;4529 -50;4527 -50;4527 -50 1;4773 -144;5031 -200;5295 -200 1;5861 -200;6394 -1;6763 388 1;6802 432;6839 480;6882 538 1;6914 581;6969 600;7022 585 1;7074 572;7112 529;7119 476 1;7140 310;7271 152;7427 97 1;7615 32;7831 -23;8080 -81 1;8085 -82;8083 -82;8083 -82 1;8360 -146;8654 -178;8965 -178 1;9028 -178;9099 -173;9168 -166 1;9182 -165;9190 -163;9205 -161 1;9278 -156;9347 -148;9415 -136 1;9437 -133;9445 -133;9447 -133 1;9507 -125;9570 -116;9635 -103 1;9681 -95;9728 -112;9758 -146 1;9788 -181;9800 -230;9785 -274 1;9745 -394;9718 -512;9718 -616 1;9718 -878;9838 -1186;10043 -1369 1;10048 -1372;10051 -1374;10058 -1380 1;10243 -1538;10508 -1644;10751 -1644 1;10994 -1644;11257 -1542;11452 -1373 1;11458 -1367;11460 -1365;11466 -1364 1;11671 -1177;11789 -869;11789 -616 1;11789 -441;11717 -246;11606 -67 1;11576 -18;11579 44;11619 94 1;11644 132;11678 151;11716 155 1;11753 159;11791 147;11817 122 1;11871 77;11935 44;12001 25 1;12194 -30;12416 -67;12682 -110 1;12967 -156;13260 -186;13564 -186 1;13889 -186;14173 -142;14439 -35 1;14695 64;14923 211;15088 414 1;15181 529;15253 669;15316 817 1;15337 863;15381 893;15431 897 1;15481 900;15529 874;15555 830 1;15641 673;15739 530;15862 404 1;16061 212;16299 65;16570 -35 1;16849 -140;17147 -186;17457 -186 1;17585 -186;17713 -174;17847 -161 1;17854 -161;17842 -163;17865 -161 1;17990 -153;18110 -138;18237 -120 1;18355 -103;18475 -82;18593 -58 1;18605 -52;18617 -50;18628 -50 1;18743 -26;18848 -1;18940 25 1;19124 80;19273 279;19273 472;19273 3299 1;19273 3915;19111 4466;18724 4844 1;18718 4850;18716 4852;18709 4858 1;18305 5243;17742 5390;17090 5390 18;-1305 3799 1;-1102 3799;-928 3780;-787 3748 1;-646 3712;-518 3673;-404 3626;-539 2884 1;-627 2918;-728 2946;-838 2966 1;-945 2984;-1050 2993;-1151 2993 1;-1365 2993;-1508 2933;-1581 2813 1;-1648 2694;-1683 2535;-1683 2333;-1683 1150;-539 1150;-539 357;-1683 357;-1683 -634;-2636 -481;-2636 2346 1;-2636 2565;-2618 2763;-2579 2941 1;-2536 3121;-2463 3274;-2361 3402 1;-2259 3526;-2123 3624;-1951 3696 1;-1781 3764;-1566 3799;-1305 3799 18;10752 -52 1;10906 -52;11038 -101;11149 -200 1;11264 -303;11323 -441;11323 -616 1;11323 -791;11264 -927;11149 -1026 1;11038 -1128;10906 -1179;10752 -1179 1;10600 -1179;10465 -1128;10350 -1026 1;10238 -927;10183 -791;10183 -616 1;10183 -441;10238 -303;10350 -200 1;10465 -101;10600 -52;10752 -52 18;10279 3722;11233 3722;11233 357;10279 357;10279 3722 18;-11963 3722;-11009 3722;-11009 357;-11963 357;-11963 3722 18;7581 3722;8534 3722;8534 1150 1;8575 1137;8637 1126;8718 1118 1;8804 1105;8877 1098;8937 1098 1;9069 1098;9191 1112;9306 1137 1;9424 1158;9523 1180;9608 1201;9768 414 1;9717 392;9655 375;9583 363 1;9510 345;9437 333;9365 325 1;9292 312;9220 303;9146 299 1;9075 290;9013 286;8962 286 1;8677 286;8415 314;8182 369 1;7950 420;7750 476;7581 536;7581 3722 18;12129 3722;13082 3722;13082 1125 1;13142 1115;13210 1110;13287 1105 1;13363 1097;13435 1092;13504 1092 1;13725 1092;13876 1156;13958 1285 1;14039 1411;14080 1630;14080 1937;14080 3722;15033 3722;15033 1821 1;15033 1592;15010 1381;14963 1195 1;14916 1007;14836 845;14726 709 1;14614 572;14463 467;14272 395 1;14083 318;13847 280;13562 280 1;13280 280;13012 301;12756 344 1;12499 382;12290 425;12129 472;12129 3722 18;15729 3616 1;15737 3607;15749 3596;15758 3588 1;15784 3562;15799 3528;15799 3491 1;15799 3491;15799 3489;15799 3487;15794 3440;15767 3400 1;15769 3404;15763 3384;15737 3354 1;15711 3321;15671 3303;15623 3306 1;15549 3318;15499 3374;15499 3441 1;15499 3441;15499 3524;15499 3524 1;15501 3579;15533 3628;15585 3648 1;15634 3667;15691 3656;15729 3616 18;-14662 3722;-13708 3722;-13708 1150 1;-13667 1137;-13605 1126;-13524 1118 1;-13439 1105;-13366 1098;-13306 1098 1;-13174 1098;-13051 1112;-12936 1137 1;-12819 1158;-12719 1180;-12634 1201;-12474 414 1;-12526 392;-12587 375;-12660 363 1;-12733 345;-12806 333;-12878 325 1;-12951 312;-13022 303;-13096 299 1;-13167 290;-13229 286;-13280 286 1;-13565 286;-13827 314;-14060 369 1;-14292 420;-14492 476;-14662 536;-14662 3722 18;-6378 3722;-5425 3722;-5425 1125 1;-5365 1115;-5297 1110;-5220 1105 1;-5143 1097;-5070 1092;-5002 1092 1;-4780 1092;-4628 1156;-4549 1285 1;-4467 1411;-4427 1630;-4427 1937;-4427 3722;-3474 3722;-3474 1821 1;-3474 1592;-3497 1381;-3544 1195 1;-3591 1007;-3669 845;-3781 709 1;-3890 572;-4042 467;-4235 395 1;-4422 318;-4658 280;-4945 280 1;-5227 280;-5495 301;-5751 344 1;-6007 382;-6217 425;-6378 472;-6378 3722 18;17092 4924 1;17677 4924;18107 4790;18385 4522 1;18665 4257;18806 3849;18806 3299;18806 472 1;18722 446;18624 422;18512 402 1;18405 375;18292 354;18173 337 1;18053 320;17931 307;17809 299 1;17689 286;17572 280;17457 280 1;17187 280;16947 320;16734 402 1;16521 478;16339 589;16189 733 1;16044 878;15934 1053;15857 1259 1;15781 1458;15743 1683;15743 1930 1;15743 2424;15866 2811;16113 3087 1;16361 3361;16717 3498;17182 3498 1;17309 3498;17427 3487;17533 3466 1;17644 3441;17750 3404;17854 3357;17854 3479 1;17854 3666;17796 3819;17680 3939 1;17570 4059;17377 4119;17105 4119 1;16896 4119;16707 4101;16543 4067 1;16379 4032;16224 3986;16074 3926;15908 4725 1;16083 4785;16272 4832;16477 4867 1;16682 4905;16887 4924;17092 4924 18;1726 3810 1;1846 3810;1965 3804;2084 3793 1;2204 3779;2314 3763;2417 3741 1;2524 3724;2619 3703;2705 3677 1;2790 3651;2859 3626;2910 3601;2782 2826 1;2675 2873;2538 2912;2365 2948 1;2199 2978;2029 2993;1854 2993 1;1581 2993;1364 2934;1201 2820 1;1039 2704;947 2550;926 2353;3088 2353 1;3094 2301;3097 2245;3102 2180 1;3105 2112;3109 2050;3109 1995 1;3109 1426;2968 998;2692 709 1;2416 414;2038 267;1559 267 1;1354 267;1154 305;958 382 1;766 459;596 572;446 722 1;298 870;177 1058;81 1285 1;-9 1507;-52 1766;-52 2065 1;-52 2311;-19 2542;49 2756 1;123 2969;231 3154;376 3312 1;524 3466;712 3588;933 3677 1;1159 3765;1422 3810;1726 3810 18;-8496 3810 1;-8376 3810;-8257 3804;-8137 3793 1;-8017 3779;-7908 3763;-7804 3741 1;-7697 3724;-7603 3703;-7516 3677 1;-7431 3651;-7363 3626;-7311 3601;-7440 2826 1;-7546 2873;-7684 2912;-7855 2948 1;-8022 2978;-8193 2993;-8368 2993 1;-8640 2993;-8857 2934;-9020 2820 1;-9182 2704;-9273 2550;-9296 2353;-7132 2353 1;-7128 2301;-7124 2245;-7119 2180 1;-7116 2112;-7113 2050;-7113 1995 1;-7113 1426;-7252 998;-7529 709 1;-7806 414;-8184 267;-8662 267 1;-8867 267;-9067 305;-9264 382 1;-9455 459;-9625 572;-9775 722 1;-9923 870;-10045 1058;-10140 1285 1;-10230 1507;-10273 1766;-10273 2065 1;-10273 2311;-10240 2542;-10171 2756 1;-10098 2969;-9990 3154;-9845 3312 1;-9696 3466;-9510 3588;-9288 3677 1;-9062 3765;-8798 3810;-8496 3810 18;-12484 -146 1;-12454 -181;-12442 -230;-12457 -274 1;-12497 -394;-12524 -512;-12524 -616 1;-12524 -619;-12502 -670;-12491 -753 1;-12484 -794;-12496 -836;-12524 -866 1;-12554 -896;-12594 -911;-12640 -905 1;-12765 -882;-12886 -866;-13002 -866 1;-13009 -866;-13043 -876;-13102 -878 1;-13139 -879;-13174 -866;-13199 -841 1;-13225 -814;-13240 -781;-13240 -745 1;-13240 -745;-13240 -300;-13240 -300 1;-13240 -230;-13188 -171;-13119 -166 1;-13079 -161;-13064 -165;-13074 -166;-13056 -164;-13037 -161 1;-12964 -156;-12895 -148;-12827 -136 1;-12806 -133;-12797 -133;-12795 -133;-12795 -132;-12793 -132;-12795 -133 1;-12735 -125;-12673 -116;-12607 -103 1;-12561 -95;-12514 -112;-12484 -146 18;-14662 -213;-13708 -213;-13708 -1479 1;-13602 -1432;-13492 -1395;-13377 -1371 1;-13261 -1346;-13137 -1333;-13006 -1333 1;-12765 -1333;-12556 -1376;-12373 -1461 1;-12189 -1546;-12034 -1666;-11911 -1819 1;-11788 -1972;-11694 -2156;-11629 -2368 1;-11566 -2582;-11535 -2819;-11535 -3078 1;-11535 -3348;-11574 -3591;-11657 -3808 1;-11732 -4027;-11846 -4210;-11995 -4358 1;-12144 -4513;-12328 -4630;-12544 -4711 1;-12763 -4796;-13009 -4838;-13287 -4838 1;-13402 -4838;-13524 -4833;-13652 -4819 1;-13776 -4811;-13898 -4798;-14022 -4781 1;-14142 -4765;-14257 -4743;-14369 -4716 1;-14478 -4697;-14576 -4673;-14662 -4646;-14662 -213 18;-17051 3810 1;-16800 3810;-16574 3769;-16373 3684 1;-16168 3598;-15993 3479;-15848 3324 1;-15703 3168;-15593 2980;-15517 2763 1;-15440 2540;-15401 2298;-15401 2033 1;-15401 1768;-15442 1526;-15523 1310 1;-15603 1092;-15716 906;-15861 754 1;-16006 600;-16182 480;-16386 395 1;-16586 310;-16808 267;-17051 267 1;-17291 267;-17512 310;-17717 395 1;-17917 480;-18092 600;-18242 754 1;-18387 906;-18502 1092;-18587 1310 1;-18669 1526;-18708 1768;-18708 2033 1;-18708 2298;-18669 2540;-18587 2763 1;-18505 2980;-18392 3168;-18247 3324 1;-18102 3479;-17931 3598;-17729 3684 1;-17525 3769;-17299 3810;-17051 3810 18;5463 3810 1;5581 3810;5701 3804;5821 3793 1;5939 3779;6051 3763;6152 3741 1;6259 3724;6356 3703;6441 3677 1;6526 3651;6594 3626;6646 3601;6518 2826 1;6411 2873;6272 2912;6103 2948 1;5936 2978;5765 2993;5590 2993 1;5318 2993;5100 2934;4938 2820 1;4775 2704;4683 2550;4663 2353;6826 2353 1;6829 2301;6834 2245;6837 2180 1;6843 2112;6844 2050;6844 1995 1;6844 1426;6706 998;6428 709 1;6151 414;5773 267;5297 267 1;5091 267;4891 305;4695 382 1;4503 459;4332 572;4183 722 1;4033 870;3911 1058;3819 1285 1;3729 1507;3684 1766;3684 2065 1;3684 2311;3719 2542;3787 2756 1;3858 2969;3967 3154;4112 3312 1;4262 3466;4446 3588;4668 3677 1;4895 3765;5160 3810;5463 3810 18;-1065 2521 1;-1018 2518;-969 2518;-911 2508 1;-910 2508;-909 2506;-907 2505 1;-830 2489;-762 2473;-704 2450 1;-702 2450;-700 2450;-698 2450 1;-670 2439;-642 2426;-612 2422 1;-545 2409;-500 2350;-503 2283 1;-509 2203;-520 2131;-520 2067 1;-520 1973;-502 1875;-490 1763 1;-487 1725;-500 1688;-525 1660 1;-550 1633;-586 1616;-623 1616;-1106 1616 1;-1170 1630;-1217 1687;-1215 1750;-1215 2333 1;-1215 2360;-1211 2386;-1206 2405 1;-1198 2474;-1136 2527;-1065 2521 18;-11490 -52 1;-11336 -52;-11204 -101;-11093 -200 1;-10978 -303;-10920 -441;-10920 -616 1;-10920 -791;-10978 -927;-11093 -1026 1;-11204 -1128;-11336 -1179;-11490 -1179 1;-11642 -1179;-11777 -1128;-11893 -1026 1;-12004 -927;-12059 -791;-12059 -616 1;-12059 -441;-12004 -303;-11893 -200 1;-11777 -101;-11642 -52;-11490 -52 18;-17051 -1307 1;-16800 -1307;-16574 -1349;-16373 -1434 1;-16168 -1521;-15993 -1639;-15848 -1794 1;-15703 -1951;-15593 -2139;-15517 -2355 1;-15440 -2579;-15401 -2820;-15401 -3085 1;-15401 -3350;-15442 -3591;-15523 -3808 1;-15603 -4027;-15716 -4211;-15861 -4365 1;-16006 -4518;-16182 -4638;-16386 -4723 1;-16586 -4808;-16808 -4851;-17051 -4851 1;-17291 -4851;-17512 -4808;-17717 -4723 1;-17917 -4638;-18092 -4518;-18242 -4365 1;-18387 -4211;-18502 -4027;-18587 -3808 1;-18669 -3591;-18708 -3350;-18708 -3085 1;-18708 -2820;-18669 -2579;-18587 -2355 1;-18505 -2139;-18392 -1951;-18247 -1794 1;-18102 -1639;-17931 -1521;-17729 -1434 1;-17525 -1349;-17299 -1307;-17051 -1307 18;-7064 -1395;-6112 -1395;-6112 -3993 1;-6052 -4004;-5983 -4008;-5907 -4013 1;-5830 -4021;-5759 -4027;-5690 -4027 1;-5468 -4027;-5317 -3961;-5235 -3833 1;-5155 -3707;-5113 -3488;-5113 -3182;-5113 -1395;-4160 -1395;-4160 -3296 1;-4160 -3527;-4183 -3737;-4230 -3923 1;-4277 -4111;-4357 -4273;-4467 -4410 1;-4579 -4547;-4730 -4652;-4921 -4723 1;-5110 -4800;-5347 -4838;-5631 -4838 1;-5913 -4838;-6181 -4818;-6438 -4774 1;-6694 -4736;-6903 -4693;-7064 -4646;-7064 -1395 18;-11099 -1644 1;-11068 -1689;-11067 -1748;-11095 -1794 1;-11120 -1834;-11128 -1842;-11120 -1827 1;-11143 -1872;-11189 -1899;-11242 -1899 1;-11246 -1897;-11251 -1895;-11258 -1894 1;-11298 -1887;-11332 -1862;-11353 -1827 1;-11358 -1822;-11364 -1814;-11375 -1799 1;-11394 -1761;-11396 -1718;-11379 -1679 1;-11362 -1639;-11328 -1611;-11287 -1602 1;-11257 -1596;-11240 -1594;-11242 -1594 1;-11188 -1581;-11133 -1601;-11099 -1644 18;-9182 -1307 1;-9063 -1307;-8944 -1314;-8824 -1326 1;-8706 -1339;-8594 -1356;-8492 -1378 1;-8385 -1395;-8289 -1416;-8204 -1440 1;-8119 -1468;-8051 -1493;-7999 -1517;-8127 -2292 1;-8234 -2246;-8372 -2205;-8542 -2171 1;-8708 -2141;-8881 -2126;-9055 -2126 1;-9327 -2126;-9545 -2184;-9707 -2299 1;-9870 -2413;-9961 -2569;-9982 -2766;-7819 -2766 1;-7816 -2817;-7810 -2873;-7808 -2939 1;-7803 -3007;-7801 -3069;-7801 -3123 1;-7801 -3692;-7939 -4120;-8217 -4410 1;-8494 -4705;-8872 -4851;-9349 -4851 1;-9553 -4851;-9754 -4813;-9950 -4736 1;-10141 -4660;-10314 -4547;-10462 -4396 1;-10611 -4248;-10733 -4060;-10827 -3833 1;-10917 -3612;-10962 -3352;-10962 -3054 1;-10962 -2807;-10926 -2575;-10858 -2362 1;-10787 -2149;-10678 -1964;-10533 -1806 1;-10383 -1652;-10198 -1530;-9976 -1440 1;-9750 -1352;-9485 -1307;-9182 -1307 18;16428 5964 1;15493 5816;15156 5633;14905 5136 1;14842 5010;14767 4893;14739 4875 1;14686 4843;13829 4769;13588 4777 1;13511 4779;12673 4786;11726 4791;10003 4801;9412 4491;8810 4801;8189 4815 1;7703 4826;7501 4814;7261 4759 1;6957 4690;6950 4690;6521 4785 1;6170 4863;5974 4881;5488 4880;5457 4880 1;4811 4880;4563 4831;4074 4600 1;3912 4524;3745 4461;3703 4461 1;3660 4461;3540 4504;3437 4556 1;2881 4838;1858 4973;1148 4859 1;1005 4835;741 4765;560 4703 1;206 4579;201 4579;-280 4737 1;-640 4854;-1173 4915;-1564 4883 1;-1876 4858;-2085 4806;-2522 4644 1;-2687 4583;-2700 4585;-2962 4691 1;-3221 4796;-3260 4801;-3912 4799 1;-4286 4797;-4700 4791;-4832 4785 1;-4964 4779;-5368 4786;-5729 4802 1;-6286 4827;-6433 4820;-6697 4760 1;-7003 4690;-7012 4690;-7420 4779 1;-8263 4964;-9117 4926;-9699 4679 1;-10091 4513;-10177 4511;-10482 4666;-10748 4801;-12238 4801;-12541 4645;-12844 4489;-13138 4645;-13432 4801;-14922 4801;-15208 4663 1;-15529 4507;-15467 4502;-16152 4744 1;-16831 4984;-17621 4945;-18238 4642 1;-19010 4261;-19482 3685;-19691 2865 1;-19908 2013;-19801 1156;-19391 468 1;-19227 194;-19067 14;-18762 -238 1;-18460 -488;-18462 -552;-18772 -793 1;-19030 -993;-19347 -1393;-19507 -1720 1;-19700 -2113;-19789 -2552;-19789 -3099 1;-19788 -3688;-19727 -3966;-19489 -4450 1;-19192 -5057;-18572 -5590;-17912 -5806 1;-17374 -5984;-16546 -5988;-15770 -5633;-15447 -5485;-15239 -5576 1;-14740 -5794;-14092 -5908;-13352 -5909 1;-12569 -5909;-12118 -5779;-11532 -5381 1;-11433 -5314;-11315 -5259;-11270 -5259 1;-11225 -5259;-11047 -5352;-10875 -5465 1;-10015 -6029;-9078 -6079;-8023 -5616;-7813 -5524;-7443 -5648 1;-6638 -5917;-5482 -5996;-4840 -5824 1;-4236 -5663;-3768 -5339;-3467 -4873 1;-3148 -4378;-3090 -4073;-3064 -2779 1;-3052 -2196;-3026 -1687;-3006 -1649 1;-2959 -1560;-2787 -1559;-2312 -1644 1;-2114 -1679;-1835 -1709;-1691 -1709 1;-1229 -1712;-888 -1486;-654 -1024 1;-541 -799;-528 -788;-245 -681 1;187 -519;243 -518;668 -662 1;965 -763;1135 -795;1448 -809 1;2091 -837;2566 -704;3131 -337 1;3264 -250;3400 -179;3432 -179 1;3464 -179;3619 -259;3777 -358 1;4137 -581;4287 -644;4688 -741 1;5298 -888;5896 -821;6519 -534;6870 -372;7177 -478 1;7625 -633;8076 -733;8550 -781 1;9020 -829;9105 -876;9182 -1133 1;9308 -1554;9694 -1943;10095 -2129 1;10456 -2299;11045 -2279;11428 -2095 1;11880 -1878;12170 -1593;12329 -1108 1;12441 -766;12455 -756;12815 -779 1;14010 -855;14639 -730;15238 -297 1;15327 -232;15435 -179;15479 -179 1;15522 -179;15686 -258;15843 -355 1;16603 -824;17454 -922;18651 -679 1;19204 -567;19417 -469;19628 -230 1;19900 79;19908 145;19908 1951;19908 2068 1;19908 3651;19886 3934;19718 4401 1;19503 5000;19140 5402;18544 5703 1;18007 5974;17155 6079;16428 5964 18;17928 5561 1;18700 5363;19232 4845;19456 4071 1;19512 3877;19525 3576;19538 2141 1;19550 942;19541 396;19509 289 1;19438 50;19214 -170;18973 -238 1;18265 -438;17233 -498;16751 -367 1;16348 -257;15993 -62;15706 208;15444 456;15306 271 1;15116 17;14791 -194;14388 -327 1;14080 -428;13997 -439;13508 -436 1;13048 -433;12442 -364;12083 -274 1;12000 -253;11998 -259;12035 -436 1;12080 -647;12030 -945;11908 -1199 1;11636 -1762;10897 -2045;10292 -1817 1;9806 -1635;9468 -1148;9468 -632;9468 -407;9216 -431 1;8866 -464;8256 -399;7783 -280 1;7323 -163;7201 -108;7046 57;6934 175;6772 37 1;5907 -704;4382 -591;3607 271;3424 474;3360 377 1;3119 21;2522 -336;2023 -420 1;1440 -518;756 -394;341 -114;129 29;28 -91 1;-139 -289;-354 -379;-661 -379;-932 -379;-932 -509 1;-933 -750;-1017 -955;-1187 -1124 1;-1437 -1374;-1550 -1391;-2246 -1283 1;-2569 -1232;-2887 -1163;-2953 -1129 1;-3248 -975;-3372 -718;-3372 -258;-3372 65;-3550 -58 1;-3801 -230;-4065 -337;-4405 -402 1;-4781 -475;-5094 -474;-5671 -398 1;-6502 -289;-6766 -202;-6943 24;-7040 149;-7232 3 1;-7499 -201;-7690 -292;-8042 -381 1;-8755 -564;-9576 -395;-10120 47 1;-10278 175;-10291 178;-10328 108 1;-10358 53;-10348 -23;-10289 -176 1;-10246 -291;-10206 -465;-10202 -563 1;-10196 -705;-10182 -736;-10133 -716 1;-9610 -509;-8452 -550;-7836 -799 1;-7626 -884;-7587 -889;-7532 -839 1;-7372 -694;-7184 -659;-6575 -659;-6548 -659 1;-5984 -659;-5837 -684;-5685 -810 1;-5627 -859;-5602 -854;-5492 -772 1;-5374 -686;-5322 -678;-4739 -666 1;-4055 -652;-3888 -680;-3692 -845 1;-3432 -1064;-3432 -1066;-3434 -2479 1;-3436 -3540;-3448 -3805;-3503 -4029 1;-3693 -4791;-4168 -5277;-4922 -5483 1;-5261 -5575;-6112 -5566;-6698 -5463 1;-7272 -5363;-7461 -5289;-7610 -5109;-7726 -4968;-7879 -5088 1;-8814 -5825;-10355 -5685;-11073 -4798;-11235 -4596;-11494 -4860 1;-11783 -5155;-12156 -5370;-12572 -5482 1;-13108 -5626;-14450 -5523;-14960 -5299 1;-15058 -5256;-15175 -5160;-15239 -5069;-15350 -4913;-15611 -5103 1;-16440 -5704;-17556 -5733;-18389 -5176 1;-18763 -4926;-18970 -4689;-19174 -4279 1;-19544 -3536;-19541 -2623;-19167 -1859 1;-18698 -903;-17669 -417;-16549 -623 1;-16267 -675;-15788 -888;-15574 -1057;-15421 -1179;-15405 -589 1;-15394 -169;-15373 26;-15332 89 1;-15235 239;-15319 237;-15504 86 1;-16274 -546;-17402 -634;-18285 -132 1;-19617 624;-19853 2734;-18732 3863 1;-17912 4689;-16505 4772;-15566 4050;-15379 3907;-15333 4019 1;-15270 4170;-15105 4323;-14923 4399 1;-14712 4487;-13672 4487;-13461 4399 1;-13264 4317;-13137 4195;-13048 4001 1;-12982 3860;-12974 3728;-12973 2871;-12973 2823 1;-12972 1843;-12978 1874;-12782 1926;-12692 1950 1;-12692 3973;-12680 4038;-12439 4250 1;-12222 4440;-12067 4471;-11387 4455 1;-10804 4441;-10780 4438;-10624 4329 1;-10492 4238;-10413 4134;-10306 3908 1;-10303 3901;-10213 3963;-10106 4044 1;-9632 4408;-9047 4566;-8312 4528 1;-7825 4503;-7365 4416;-7096 4297 1;-6933 4226;-6914 4225;-6848 4284 1;-6702 4417;-6483 4457;-5908 4459 1;-5355 4461;-5138 4426;-5010 4317 1;-4958 4272;-4918 4279;-4753 4362 1;-4571 4454;-4518 4461;-3955 4460 1;-3267 4459;-3106 4414;-2910 4168;-2797 4027;-2623 4147 1;-2311 4362;-2052 4456;-1635 4505 1;-1021 4577;-348 4454;37 4200;186 4101;437 4238 1;800 4435;1069 4503;1588 4529 1;1962 4547;2134 4535;2508 4464 1;3072 4358;3355 4230;3495 4017 1;3552 3931;3607 3861;3617 3861 1;3627 3861;3710 3925;3802 4004 1;4053 4219;4484 4414;4868 4487 1;5440 4594;6391 4505;6861 4299;7033 4223;7198 4332 1;7357 4438;7382 4441;8005 4453 1;8611 4465;8658 4460;8826 4373 1;8923 4323;9058 4212;9126 4127;9248 3974;9260 2937;9272 1901;9360 1902 1;9541 1903;9543 1914;9556 2969;9568 3974;9690 4127 1;9758 4212;9892 4322;9989 4371 1;10149 4453;10221 4461;10767 4460 1;11260 4459;11397 4446;11528 4387 1;11682 4317;11694 4317;11848 4387 1;11979 4446;12117 4459;12611 4460 1;13162 4461;13230 4453;13396 4369;13577 4278;13732 4359 1;13871 4432;13961 4441;14551 4441;15214 4441;15197 4626 1;15173 4869;15240 5059;15408 5233 1;15568 5397;15799 5483;16366 5586 1;16835 5672;17538 5661;17928 5561;17928 5561 18;-13184 -2139 1;-13282 -2139;-13381 -2152;-13479 -2177 1;-13572 -2202;-13648 -2234;-13708 -2274;-13708 -3993 1;-13662 -4004;-13602 -4008;-13530 -4013 1;-13457 -4021;-13379 -4027;-13293 -4027 1;-13032 -4027;-12837 -3936;-12704 -3756 1;-12572 -3582;-12506 -3348;-12506 -3054 1;-12506 -2443;-12733 -2139;-13184 -2139 18;-13248 -2631 1;-13034 -2631;-12976 -2876;-12976 -3090 1;-12976 -3284;-13054 -3505;-13248 -3506;-13248 -2631 18;17360 2730 1;16930 2730;16714 2463;16714 1930 1;16714 1675;16776 1464;16900 1297 1;17024 1130;17212 1047;17464 1047 1;17548 1047;17623 1052;17687 1060 1;17750 1065;17807 1072;17854 1080;17854 2603 1;17794 2636;17720 2666;17636 2691 1;17550 2718;17459 2730;17360 2730 18;17409 2232;17409 1571 1;17201 1492;17180 1713;17180 1926 1;17178 2120;17192 2338;17409 2232 18;-15193 -49784 1;-14217 -49499;-13415 -49441;-12989 -48519 1;-12566 -47603;-11592 -45828;-12581 -46029 1;-14699 -46461;-17951 -46822;-17192 -48845 1;-16847 -49781;-16020 -50025;-15193 -49784 18;-18644 -49113 1;-16846 -47471;-15545 -46883;-13137 -46518 1;-12026 -46350;-11285 -46033;-10331 -46624 1;-9588 -47084;-8719 -47865;-8212 -47154 1;-7772 -46538;-7013 -45793;-7630 -45353 1;-9702 -43873;-11427 -43443;-13878 -44135 1;-16573 -44897;-18495 -45269;-19915 -47683 1;-20238 -48232;-20561 -48935;-20021 -49272 1;-19643 -49507;-19340 -49380;-18909 -49272 1;-18789 -49242;-18735 -49197;-18644 -49113 18;-14392 -50181 1;-14381 -49674;-14435 -47077;-14246 -46608 1;-14027 -46065;-13484 -45210;-13406 -44631;-12944 -42978;-12152 -46461 1;-12371 -47163;-12539 -47623;-12875 -48268 1;-13136 -48770;-13281 -49147;-13796 -49381;-8047 -47393 1;-8861 -46910;-9236 -46594;-10115 -46243 1;-11056 -45866;-11873 -45554;-12649 -46207 1;-13681 -47074;-14003 -47947;-15310 -48274 1;-15927 -48429;-16204 -47931;-16820 -47771 1;-17810 -47514;-18814 -47421;-19319 -48310;-19769 -49119;-7400 -46782 1;-8361 -45993;-8885 -45517;-10097 -45235 1;-11152 -44989;-12287 -44656;-13216 -45654 1;-13781 -46261;-13659 -46705;-14781 -47249 1;-15525 -47611;-16019 -46869;-16910 -46476 1;-17867 -46054;-18629 -46273;-19499 -46853;-20470 -47789;-7310 -45847 1;-8637 -44962;-9328 -44361;-10905 -44121 1;-11609 -44013;-12029 -44131;-12649 -44481 1;-12883 -44612;-12993 -44687;-13225 -44822 1;-13381 -44913;-13594 -44817;-13638 -44642 1;-13729 -44278;-14245 -44136;-14537 -44373 1;-14929 -44690;-15109 -44875;-15544 -45128 1;-15969 -45376;-16271 -45501;-16749 -45379 1;-17381 -45219;-17745 -44985;-18367 -45181;-19049 -45397;-16623 -46279;-17072 -46764;-14397 -45742 1;-14115 -45417;-13985 -45095;-14103 -44970 1;-14223 -44844;-14555 -44959;-14897 -45229 16;-15275 -45591 1;-15547 -45911;-15670 -46224;-15554 -46346 1;-15439 -46467;-15127 -46365;-14799 -46118 16;-11871 -51383 1;-12194 -50957;-12110 -50349;-11683 -50027 1;-11256 -49703;-10649 -49787;-10326 -50214 1;-10003 -50641;-10087 -51248;-10514 -51571 1;-10941 -51894;-11548 -51810;-11871 -51383 18;-8669 -51265 1;-8967 -51745;-9599 -51893;-10079 -51595 1;-10559 -51297;-10707 -50665;-10409 -50184 1;-10111 -49703;-9479 -49556;-8998 -49854 1;-8518 -50153;-8370 -50784;-8669 -51265 18;-9687 -48591 1;-9115 -48519;-8593 -48925;-8521 -49497 1;-8449 -50069;-8856 -50592;-9428 -50663 1;-10000 -50735;-10523 -50329;-10594 -49757 1;-10665 -49184;-10259 -48662;-9687 -48591 18;-10193 -48866 1;-9783 -49241;-9754 -49877;-10129 -50288 1;-10504 -50698;-11141 -50727;-11551 -50351 1;-11961 -49977;-11990 -49340;-11615 -48929 1;-11240 -48519;-10603 -48491;-10193 -48866 18;-9063 -47648 1;-8585 -47931;-8427 -48547;-8709 -49025 1;-8992 -49502;-9608 -49661;-10086 -49378 1;-10563 -49095;-10721 -48479;-10439 -48001 1;-10157 -47524;-9541 -47365;-9063 -47648 18;-11816 -48004 1;-11539 -47531;-10931 -47373;-10458 -47651 1;-9986 -47928;-9827 -48536;-10105 -49008 1;-10382 -49481;-10990 -49639;-11463 -49361 1;-11935 -49084;-12093 -48477;-11816 -48004 18;-17713 -51067;-15891 -51625;-15183 -49263;-17007 -49375;-17713 -51067 18;-13406 -45295 1;-14143 -44522;-16113 -43986;-15247 -43361 1;-14461 -42794;-13298 -41094;-13201 -42059;-12979 -44291;-13406 -45295 18;-18763 -51061;-18781 -41352;-20529 -42915;-7231 -42840;-11472 -46906 1;-11715 -47233;-12177 -47303;-12505 -47061 1;-12833 -46819;-12902 -46357;-12660 -46029 1;-12418 -45701;-11955 -45631;-11627 -45873 1;-11299 -46115;-11230 -46578;-11472 -46906 18;-13281 -51435 1;-13605 -51008;-13521 -50401;-13093 -50078 1;-12667 -49755;-12059 -49839;-11737 -50265 1;-11414 -50692;-11498 -51299;-11925 -51623 1;-12351 -51945;-12959 -51861;-13281 -51435 18;-25283 -38824;-14902 -45736;-44934 -51808;Click menu View > Overprinting simulation or press F4 to toggle diff --git a/examples/sprint sample.omap b/examples/sprint sample.omap index 7025e86c0..85e8091d2 100644 --- a/examples/sprint sample.omap +++ b/examples/sprint sample.omap @@ -84,7 +84,7 @@ Competitors violating this rule will be disqualified.</span> The minimum gap between buildings and between buildings and other impassable features shall be 0.40 mm. The black screen percentage should be chosen according to the terrain. A dark screen gives a better contrast to passable areas, such as streets, stairways and canopies, while a light screen makes contours and course overprint more clearly visible (which can be important in very densely built up urban terrain and in steep urban terrain). The black screen shall be the same for the whole map. <span style="color:magenta">It is forbidden to pass through or over a building! -Competitors violating this rule will be disqualified.</span>Do not use this symbol on its own!Do not use this symbol on its own!A building is a relatively permanent construction having a roof. Buildings within symbol area with forbidden access (527.1) may just be represented in a simplified manner.Areas totally contained within a building shall be mapped as being a part of the building. +Competitors violating this rule will be disqualified.</span>Do not use this symbol on its own!Do not use this symbol on its own!A building is a relatively permanent construction having a roof. Buildings within symbol area with forbidden access (527.1) may just be represented in a simplified manner.Areas totally contained within a building shall be mapped as being a part of the building. The minimum gap between buildings and between buildings and other impassable features shall be 0.40 mm. The black screen percentage should be chosen according to the terrain. A dark screen gives a better contrast to passable areas, such as streets, stairways and canopies, while a light screen makes contours and course overprint more clearly visible (which can be important in very densely built up urban terrain and in steep urban terrain). The black screen shall be the same for the whole map. @@ -179,7 +179,7 @@ An out-of-bounds area is shown with vertical stripes. A bounding line may be dra - no line indicates no marking on the ground. <span style="color:magenta">It is forbidden to cross an out-of-bounds area! -Competitors violating this rule will be disqualified.</span>A solid line indicates that the boundary is marked continuously (tapes, etc.) on the ground.A dashed line indicates intermittent marking on the ground.The location of a first aid post.-1500 0;1500 0;0 -1500;0 1500;The location of a refreshment point which is not at a control or along the marked route.-1340 -1395;-820 1380;1340 -1395;820 1380;0 -1770 1;600 -1770;1200 -1620;1340 -1395 1;1200 -1170;600 -1020;0 -1020 1;-600 -1020;-1200 -1170;-1340 -1395 1;-1200 -1620;-600 -1770;0 -1770;-820 1380 1;-680 1680;680 1680;820 1380;Obvious temporary constructions like platforms for spectators and speaker, closed area for spectators, outside restaurant areas, etc. shall be represented in plan shape. +Competitors violating this rule will be disqualified.</span>A solid line indicates that the boundary is marked continuously (tapes, etc.) on the ground.A dashed line indicates intermittent marking on the ground.The location of a first aid post.-1500 0;1500 0;0 -1500;0 1500;The location of a refreshment point which is not at a control or along the marked route.-1340 -1395;-820 1380;1340 -1395;820 1380;0 -1770 1;600 -1770;1200 -1620;1340 -1395 1;1200 -1170;600 -1020;0 -1020 1;-600 -1020;-1200 -1170;-1340 -1395 1;-1200 -1620;-600 -1770;0 -1770;-820 1380 1;-680 1680;680 1680;820 1380;Obvious temporary constructions like platforms for spectators and speaker, closed area for spectators, outside restaurant areas, etc. shall be represented in plan shape. <span style="color:magenta">It is forbidden to enter a temporary construction or closed area! Competitors violating this rule will be disqualified.</span>This symbol provides a simple and quick way to make training courses. diff --git a/examples/src/complete map.xmap b/examples/src/complete map.xmap index c030baf39..3e5f6bed0 100644 --- a/examples/src/complete map.xmap +++ b/examples/src/complete map.xmap @@ -1,12 +1,8 @@ - - - - - - + + @@ -1898,28 +1894,7 @@ Competitors violating this rule will be disqualified.</span> Do not use this symbol on its own! - - - - - - - - - - - - - - - - - - - - - - + A building is a relatively permanent construction having a roof. Buildings within symbol area with forbidden access (527.1) may just be represented in a simplified manner.Areas totally contained within a building shall be mapped as being a part of the building. @@ -2722,28 +2697,7 @@ Competitors violating this rule will be disqualified.</span> A dashed line indicates intermittent marking on the ground. - - - - - - - - - - - - - - - - - - - - - - + The location of a first aid post. @@ -74871,9 +74825,9 @@ Well; Small erosion gully - - - + + + diff --git a/examples/src/forest sample.xmap b/examples/src/forest sample.xmap index e5a999117..2e16f7409 100644 --- a/examples/src/forest sample.xmap +++ b/examples/src/forest sample.xmap @@ -1,7 +1,9 @@ - + + + @@ -2496,28 +2498,7 @@ A bounding line may be drawn if there is no natural boundary, as follows: A dashed line indicates intermittent marking on the ground. - - - - - - - - - - - - - - - - - - - - - - + An area presenting danger to the competitor is shown with cross-hatched diagonal lines. @@ -20535,8 +20516,8 @@ The purple line will extend a bit into the finish symbol. This is a shortcoming - - + + @@ -20548,1504 +20529,7 @@ The purple line will extend a bit into the finish symbol. This is a shortcoming - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/examples/src/overprinting.xmap b/examples/src/overprinting.xmap index d8a6d1f6e..318fa4458 100644 --- a/examples/src/overprinting.xmap +++ b/examples/src/overprinting.xmap @@ -1,12 +1,8 @@ - - - - - - + + @@ -2502,28 +2498,7 @@ A bounding line may be drawn if there is no natural boundary, as follows: A dashed line indicates intermittent marking on the ground. - - - - - - - - - - - - - - - - - - - - - - + An area presenting danger to the competitor is shown with cross-hatched diagonal lines. @@ -7132,8 +7107,8 @@ overprinting preview. - - + + diff --git a/examples/src/sprint sample.xmap b/examples/src/sprint sample.xmap index d73d6c054..4409f45f1 100644 --- a/examples/src/sprint sample.xmap +++ b/examples/src/sprint sample.xmap @@ -1,8 +1,7 @@ - - + +proj=utm +zone=32 +datum=WGS84 @@ -1855,28 +1854,7 @@ Competitors violating this rule will be disqualified.</span> Do not use this symbol on its own! - - - - - - - - - - - - - - - - - - - - - - + A building is a relatively permanent construction having a roof. Buildings within symbol area with forbidden access (527.1) may just be represented in a simplified manner.Areas totally contained within a building shall be mapped as being a part of the building. @@ -2679,28 +2657,7 @@ Competitors violating this rule will be disqualified.</span> A dashed line indicates intermittent marking on the ground. - - - - - - - - - - - - - - - - - - - - - - + The location of a first aid post. @@ -16229,8 +16186,8 @@ The purple line will extend a bit into the finish symbol. This is a shortcoming - - + + diff --git a/help/tip-of-the-day/tips_fr.txt b/help/tip-of-the-day/tips_fr.txt new file mode 100644 index 000000000..6322599c8 --- /dev/null +++ b/help/tip-of-the-day/tips_fr.txt @@ -0,0 +1,16 @@ +

Bienvenue dans OpenOrienteering Mapper !

Si c'est la première fois que vous utilisez ce logiciel, prenez le temps de lire ceci.

Il est possible d'accéder aux préférences et de personnaliser la configuration du logiciel. Pour des conseils détaillés sur l'utilisation de Mapper, consultez le manuel.

Conseils pour commencer tout de suite:
- Créer ou charger une carte avec les boutons à gauche
- Maintenir appuyer la molette de la souris pour déplacer la carte
- Pour zoomer, utiliser la molette de la souris, si disponible
- Lire les conseils dans la barre d'état (en bas de l'écran) afin d'apprendre à utiliser les outils. +

Exemples

+Lors de l'édition d'une carte, appuyer sur Tab pour basculer rapidement entre l'outil d'édition et les outils de dessin. +Une carte avec peu de symboles bien choisis sera bien meilleure qu'une carte encombrée de symboles inutiles.

Eduard Imhof +Les objets inutiles pour les compétiteurs dans une course d'orientation de sprint ne devraient pas être cartographiés. Par exemple les corbeilles de rue, les bouches d'incendie, les parcmètres, les révèrbères sont des détails inutiles qui encombrent la carte. +L'objectif du cartographe est de produire une carte précise et lisible en appliquant les principes spécifiques et généraux suivant : sélection, simplification et exagération. +Cartographier des structures multi-niveaux (pont, passages souterrains ou batîments souterrains) est source de confusion. En général, seul le "niveau principal de course" doit apparaître. Cependant les passages souterrains, tunnel éclairés ou les passages aériens comme les ponts qui sont utiles pour les orienteurs doivent être cartographiés. +Toutes les largeurs de lignes et les tailles des symboles doivent conserver leur valeur spécifiée. Certaines dimensions minimales doivent être respectées pour apparaître correctement à l'impression et permettre une bonne lisibilité de la carte. +Écart minimum entre deux symboles de ligne de la même couleur :
en brun ou noir : 0,15 mm
en bleu : 0,25 mm +Écart minimum entre deux symboles de surface de la même couleur : en noir : 0,15 mm +Pour les lignes en pointillés : au moins deux pointillés doivent apparaître +Pour les lignes en tirets : au moins deux tirets doivent apparaître +Les surfaces délimitées par des lignes tirets doivent avoir un diamètre au moins égal à 1,5 mm et être composées d'au moins 5 tirets +Les surfaces de couleurs doivent avoir un diamètre mininum :
Bleu, vert, gris ou jaune en plein : 0,5 mm²;
Pointillés noirs : 0,5 mm²;
Bleu, marron, vert ou jaune en pointillés : 1,0 mm² +Tous les objets plus petits que les dimensions minimums doivent être exagérées (agrandies sur la carte) ou ne pas apparaître, en fonction de leur utilité ou non pour les orienteurs. +La taille d'une carte de sprint ne doit pas dépasser le format A4. diff --git a/help/tip-of-the-day/tips_uk.txt b/help/tip-of-the-day/tips_uk.txt new file mode 100644 index 000000000..676baf480 --- /dev/null +++ b/help/tip-of-the-day/tips_uk.txt @@ -0,0 +1,16 @@ +

Вітаємо в OpenOrienteering Mapper!

Якщо ви запустили цю програму вперше, вам можуть бути цікавими наші поради.

Можливо ви захочете переглянути налаштування щоб налаштувати програму на свій смак. Детальні поради щодо використання Mapper можна знайти у вбудованій довідці.

Швидкий старт:
- Створіть або відкрийте карту за допомогою кнопок ліворуч
- Утримуйте середню кнопку миші щоб переміщувати карту
- Віддаляйте або наближайте карту за допомогою коліщатка на миші
- Читайте підказки у рядку статусу в нижній частині вікна щоб дізнатися як можуть працювати інструменти. +

Зразки

+Під час креслення карти, використовуйте Tab щоб швидко переключатися між інструментами креслення і редагування. +A map with few well chosen features will give a much better map than a map cluttered with many insignificant features. Eduard Imhof +Не варто зображати на спринтерській карті об'єкти, що є неважливими для учасника змагань. Прикладами таких об'єктів є сміттєві урни, пожежні гідранти, парковочні автомати та ліхтарні стовпи - це лише навантажує карту непотрібними деталями. +Кінцевою задачею картографа є випуск точної чіткої карти, застосовуючи при цьому специфікацію і прийоми генералізації, такі як вибіркове відображення, спрощення або перебільшення. +Зображення багаторівневих конструкцій (мостів, підземних переходів або інших споруд) спантеличує. У загальному випадку лише головний "біговий" рівень має бути зображений. Однак, проходи (підземні переходи, освічені тунелі, мости), що важливі для учасників змагань, мають бути показані. +Товщина ліній та розміри знаків повинні точно відповідати визначеним величинам. Також мають бути витримані певні мінімальні розміри. Ці вимоги забезпечують чіткість карти незалежно від технології друку. +Мінімальна відстань між двома лінійними знаками однакового кольору - коричневий або чорний: 0.15 мм, синій: 0.25 мм +Мінімальна відстань між лінією та точковим об'єктом чорного кольору - 0.15 мм +Найкоротша лінія з точок: мінімум дві точки +Найкоротша лінія зі штрихами: мінімум два штрихи +Мінімальна площа обнесена контуром: діаметр 1.5 мм і 5 точок +Мінімальні площі для об'єктів певних кольорів:
Синій, зелений, сірий або повний жовтий: 0.5 мм2;
Заповнення чорними точками: 0.5 мм2;
Заповнення синіми, коричневими, зеленими чи жовтими точками: 1.0 мм2 +Всі елементи креслення що менші за мінімальні дозволені, мають бути збільшені, або упущені, в залежності від того наскільки вони важливі для учасника змагань. +Формат карти для спринту не повинен перевищувати DIN A4. diff --git a/images/copy-coords.png b/images/copy-coords.png new file mode 100644 index 000000000..05e3deadf Binary files /dev/null and b/images/copy-coords.png differ diff --git a/images/magnifying-glass-12.png b/images/magnifying-glass-12.png deleted file mode 100644 index 4e5d80190..000000000 Binary files a/images/magnifying-glass-12.png and /dev/null differ diff --git a/images/magnifying-glass.png b/images/magnifying-glass.png new file mode 100644 index 000000000..83712b0b1 Binary files /dev/null and b/images/magnifying-glass.png differ diff --git a/images/mapper-icon/Mapper.ico b/images/mapper-icon/Mapper.ico index d53d4f869..52ac7f900 100644 Binary files a/images/mapper-icon/Mapper.ico and b/images/mapper-icon/Mapper.ico differ diff --git a/oo-mapper-version.pri b/oo-mapper-version.pri index cc5b78c00..45ee8191e 100644 --- a/oo-mapper-version.pri +++ b/oo-mapper-version.pri @@ -1,4 +1,4 @@ # Generated in CMakeLists.txt, do not edit here. Mapper_VERSION_MAJOR = 0 Mapper_VERSION_MINOR = 6 -Mapper_VERSION_PATCH = 1 +Mapper_VERSION_PATCH = 2 diff --git a/oo-mapper.pro b/oo-mapper.pro index 720421411..207348d66 100644 --- a/oo-mapper.pro +++ b/oo-mapper.pro @@ -1,6 +1,6 @@ # # Copyright 2012, 2013, 2014 Thomas Schöps -# Copyright 2012-2015 Kai Pastor +# Copyright 2012-2016 Kai Pastor # # This file is part of OpenOrienteering. # @@ -67,6 +67,11 @@ addPrerequisite(src, qbezier, 3rd-party/qbezier) !android:addPrerequisite(src, qtsingleapplication, 3rd-party/qtsingleapplication) !linux:addPrerequisite(src, proj, 3rd-party/proj) android:addPrerequisite(src, proj, 3rd-party/proj) +CONFIG(gdal) { + addPrerequisite(src, gdal, 3rd-party/gdal) + !linux:gdal.depends += proj + android:gdal.depends += proj +} addPrerequisite(src, licensing, doc/licensing) !android:addPrerequisite(src, printsupport, src/printsupport) # Doxygen: Separate test and prerequisite, or Qt Creator gets confused. @@ -139,6 +144,7 @@ SUBDIRS += \ manual \ examples \ symbol_sets \ + translations \ src manual.subdir = doc/manual diff --git a/packaging/CMakeLists.txt b/packaging/CMakeLists.txt index ae3739051..c089bd7d6 100644 --- a/packaging/CMakeLists.txt +++ b/packaging/CMakeLists.txt @@ -273,6 +273,22 @@ if(Mapper_PACKAGE_PROJ) list(APPEND MAPPER_LIB_HINTS ${PROJ_BINARY_DIR}) endif() +if(Mapper_PACKAGE_GDAL) + install( + DIRECTORY "${GDAL_BINARY_DIR}/../share/gdal" + DESTINATION "${MAPPER_DATA_DESTINATION}") + if(WIN32) + set(GDAL_LIB_SUFFIX -20) + else() + set(GDAL_LIB_SUFFIX "") + endif() + list(APPEND MAPPER_LIBS gdal${GDAL_LIB_SUFFIX}) + list(APPEND MAPPER_LIB_HINTS ${GDAL_BINARY_DIR}) + if(WIN32) + list(APPEND MAPPER_LIBS tiff-5 lzma-5) + endif() +endif() + unset(MAPPER_QT_PLUGINS) if(Mapper_PACKAGE_QT) set(QT_LIB_SUFFIX "") diff --git a/resources.qrc b/resources.qrc index e999ba348..3d53f1618 100644 --- a/resources.qrc +++ b/resources.qrc @@ -12,6 +12,7 @@ images/compass.png images/control.png images/copy.png + images/copy-coords.png images/cursor-crosshair.png images/cursor-cut.png images/cursor-delete.png @@ -45,7 +46,7 @@ images/grid.png images/group.png images/help.png - images/magnifying-glass-12.png + images/magnifying-glass.png images/mapper.png images/minus.png images/move.png @@ -116,4 +117,10 @@ help/tip-of-the-day/tips_de.txt + + help/tip-of-the-day/tips_fr.txt + + + help/tip-of-the-day/tips_uk.txt + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bb163eaf5..292fcc884 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,6 @@ # -# Copyright 2012, 2013, 2014 Thomas Schöps -# Copyright 2012-2015 Kai Pastor +# Copyright 2012-2014 Thomas Schöps +# Copyright 2012-2016 Kai Pastor # # This file is part of OpenOrienteering. # @@ -141,7 +141,9 @@ set(Mapper_Common_SRCS file_format_ocad8.cpp file_format_xml.cpp + fileformats/ocd_file_export.cpp fileformats/ocd_file_format.cpp + fileformats/ocd_file_import.cpp fileformats/ocd_types.cpp gui/about_dialog.cpp @@ -166,12 +168,15 @@ set(Mapper_Common_SRCS gui/widgets/compass_display.cpp gui/widgets/crs_param_widgets.cpp gui/widgets/crs_selector.cpp + gui/widgets/editor_settings_page.cpp + gui/widgets/general_settings_page.cpp gui/widgets/home_screen_widget.cpp gui/widgets/key_button_bar.cpp gui/widgets/mapper_proxystyle.cpp gui/widgets/measure_widget.cpp gui/widgets/pie_menu.cpp gui/widgets/segmented_button_layout.cpp + gui/widgets/settings_page.cpp gui/widgets/symbol_dropdown.cpp gui/widgets/symbol_render_widget.cpp gui/widgets/symbol_tooltip.cpp @@ -253,7 +258,8 @@ set(Mapper_Common_MOC_INPUT core/georeferencing.h core/map_printer.h - fileformats/ocd_file_format_p.h + fileformats/ocd_file_export.h + fileformats/ocd_file_import.h gui/about_dialog.h gui/autosave_dialog.h @@ -268,7 +274,6 @@ set(Mapper_Common_MOC_INPUT gui/print_widget.h gui/select_crs_dialog.h gui/settings_dialog.h - gui/settings_dialog_p.h gui/text_browser_dialog.h gui/widgets/action_grid_bar.h @@ -276,12 +281,15 @@ set(Mapper_Common_MOC_INPUT gui/widgets/compass_display.h gui/widgets/crs_param_widgets.h gui/widgets/crs_selector.h + gui/widgets/editor_settings_page.h + gui/widgets/general_settings_page.h gui/widgets/home_screen_widget.h gui/widgets/key_button_bar.h gui/widgets/mapper_proxystyle.h gui/widgets/measure_widget.h gui/widgets/pie_menu.h gui/widgets/segmented_button_layout.h + gui/widgets/settings_page.h gui/widgets/symbol_dropdown.h gui/widgets/symbol_render_widget.h gui/widgets/symbol_tooltip.h @@ -312,9 +320,11 @@ set(Mapper_Common_HEADERS fileformats/ocd_types_v9.h fileformats/ocd_types_v10.h fileformats/ocd_types_v11.h + fileformats/ocd_types_v12.h gui/point_handles.h + util/backports.h util/scoped_signals_blocker.h map_part.h @@ -324,6 +334,7 @@ set(Mapper_Common_HEADERS renderable_implementation.h symbol.h undo.h + util_gui.h ) qt5_wrap_cpp(Mapper_Common_MOC ${Mapper_Common_MOC_INPUT} TARGET Mapper_Common) @@ -343,7 +354,8 @@ qt5_add_resources(Mapper_RESOURCES_RCC ${Mapper_RESOURCES} OPTIONS -no-compress) add_library(Mapper_Common STATIC ${Mapper_Common_SRCS} ${Mapper_Common_MOC} - ${Mapper_Common_HEADERS} + ${Mapper_Common_MOC_INPUT} # for IDE + ${Mapper_Common_HEADERS} # for IDE ${Mapper_RESOURCES_RCC} ) add_dependencies(Mapper_Common @@ -368,7 +380,14 @@ if(Qt5PrintSupport_FOUND) Qt5::PrintSupport ) endif() - +if(TARGET mapper-gdal) + target_link_libraries(Mapper_Common mapper-gdal) +endif() +target_compile_definitions(Mapper_Common PRIVATE + QT_NO_CAST_FROM_ASCII + QT_NO_CAST_TO_ASCII + QT_USE_QSTRINGBUILDER +) qt5_translations_sources( SOURCES ${Mapper_Common_SRCS} ${Mapper_COMMON_MOC_INPUT} @@ -408,6 +427,11 @@ target_link_libraries(Mapper Mapper_Common doc-licensing ) +target_compile_definitions(Mapper PRIVATE + QT_NO_CAST_FROM_ASCII + QT_NO_CAST_TO_ASCII + QT_USE_QSTRINGBUILDER +) install(TARGETS Mapper RUNTIME DESTINATION "${MAPPER_RUNTIME_DESTINATION}" @@ -446,4 +470,5 @@ endforeach() set(MAPPER_PRO_GENERATOR "Generated in CMakeLists.txt from src.pro.in") string(REPLACE ";" " \\\n " MAPPER_PRO_HEADERS "${Mapper_Common_MOC_INPUT};${Mapper_Common_HEADERS}") string(REPLACE ";" " \\\n " MAPPER_PRO_SOURCES "${Mapper_Common_SRCS}") -configure_file(${PROJECT_SOURCE_DIR}/src/src.pro.in ${PROJECT_SOURCE_DIR}/src/src.pro @ONLY) +configure_file(src.pro.in src.pro.tmp @ONLY) +execute_process(COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_BINARY_DIR}/src.pro.tmp" "${CMAKE_CURRENT_SOURCE_DIR}/src.pro") diff --git a/src/color_dock_widget.cpp b/src/color_dock_widget.cpp index 8bb801b2d..b8d760fa7 100644 --- a/src/color_dock_widget.cpp +++ b/src/color_dock_widget.cpp @@ -45,36 +45,38 @@ ColorWidget::ColorWidget(Map* map, MainWindow* window, QWidget* parent) { react_to_changes = true; - setWhatsThis("See more"); + setWhatsThis(Util::makeWhatThis("color_dock_widget.html")); // Color table - color_table = new QTableWidget(map->getNumColors(), 6); + color_table = new QTableWidget(map->getNumColors(), 7); color_table->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::AnyKeyPressed); color_table->setSelectionMode(QAbstractItemView::SingleSelection); color_table->setSelectionBehavior(QAbstractItemView::SelectRows); color_table->verticalHeader()->setVisible(false); color_table->setHorizontalHeaderLabels(QStringList() << - "" << tr("Name") << tr("Spot color") << tr("CMYK") << tr("RGB") << tr("K.o.") << tr("Opacity") ); + QString{} << tr("Name") << tr("Spot color") << tr("CMYK") << tr("RGB") << tr("K.o.") << tr("Opacity") ); color_table->setItemDelegateForColumn(0, new ColorItemDelegate(this)); + color_table->setItemDelegateForColumn(6, new PercentageDelegate(this)); + color_table->setColumnHidden(6, true); QMenu* new_button_menu = new QMenu(this); (void) new_button_menu->addAction(tr("New"), this, SLOT(newColor())); duplicate_action = new_button_menu->addAction(tr("Duplicate"), this, SLOT(duplicateColor())); - duplicate_action->setIcon(QIcon(":/images/tool-duplicate.png")); + duplicate_action->setIcon(QIcon(QString::fromLatin1(":/images/tool-duplicate.png"))); // Buttons - QToolButton* new_button = newToolButton(QIcon(":/images/plus.png"), tr("New")); + QToolButton* new_button = newToolButton(QIcon(QString::fromLatin1(":/images/plus.png")), tr("New")); new_button->setPopupMode(QToolButton::DelayedPopup); // or MenuButtonPopup new_button->setMenu(new_button_menu); - delete_button = newToolButton(QIcon(":/images/minus.png"), tr("Delete")); + delete_button = newToolButton(QIcon(QString::fromLatin1(":/images/minus.png")), tr("Delete")); SegmentedButtonLayout* add_remove_layout = new SegmentedButtonLayout(); add_remove_layout->addWidget(new_button); add_remove_layout->addWidget(delete_button); - move_up_button = newToolButton(QIcon(":/images/arrow-up.png"), tr("Move Up")); + move_up_button = newToolButton(QIcon(QString::fromLatin1(":/images/arrow-up.png")), tr("Move Up")); move_up_button->setAutoRepeat(true); - move_down_button = newToolButton(QIcon(":/images/arrow-down.png"), tr("Move Down")); + move_down_button = newToolButton(QIcon(QString::fromLatin1(":/images/arrow-down.png")), tr("Move Down")); move_down_button->setAutoRepeat(true); SegmentedButtonLayout* up_down_layout = new SegmentedButtonLayout(); @@ -82,10 +84,10 @@ ColorWidget::ColorWidget(Map* map, MainWindow* window, QWidget* parent) up_down_layout->addWidget(move_down_button); // TODO: In Mapper >= 0.6, switch to ColorWidget (or generic) translation context. - edit_button = newToolButton(QIcon(":/images/settings.png"), QApplication::translate("MapEditorController", "&Edit").remove(QChar('&'))); + edit_button = newToolButton(QIcon(QString::fromLatin1(":/images/settings.png")), QApplication::translate("MapEditorController", "&Edit").remove(QLatin1Char('&'))); edit_button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); - QToolButton* help_button = newToolButton(QIcon(":/images/help.png"), tr("Help")); + QToolButton* help_button = newToolButton(QIcon(QString::fromLatin1(":/images/help.png")), tr("Help")); help_button->setAutoRaise(true); // The buttons row layout @@ -93,7 +95,7 @@ ColorWidget::ColorWidget(Map* map, MainWindow* window, QWidget* parent) buttons_group_layout->addLayout(add_remove_layout); buttons_group_layout->addLayout(up_down_layout); buttons_group_layout->addWidget(edit_button); - buttons_group_layout->addWidget(new QLabel(" "), 1); + buttons_group_layout->addWidget(new QLabel(QString::fromLatin1(" ")), 1); buttons_group_layout->addWidget(help_button); // The layout of all components below the table @@ -159,7 +161,7 @@ QToolButton* ColorWidget::newToolButton(const QIcon& icon, const QString& text) button->setToolTip(text); button->setIcon(icon); button->setText(text); - button->setWhatsThis("See more"); + button->setWhatsThis(whatsThis()); return button; } @@ -269,7 +271,7 @@ void ColorWidget::editCurrentColor() void ColorWidget::showHelp() const { - Util::showHelp(window, "color_dock_widget.html", ""); + Util::showHelp(window, "color_dock_widget.html"); } void ColorWidget::cellChange(int row, int column) @@ -289,27 +291,12 @@ void ColorWidget::cellChange(int row, int column) } else if (column == 6) // Opacity { - bool ok = true; - float fvalue; - - if (text.endsWith('%')) - text.chop(1); - - fvalue = text.toFloat(&ok) / 100.0f; - - if (fvalue < 0.0f || fvalue > 1.0f) - ok = false; - - if (ok) + auto opacity = color_table->item(row, column)->data(Qt::DisplayRole).toFloat(); + if (!qFuzzyCompare(1.0f+opacity, 1.0f+color->getOpacity())) { - color->setOpacity(fvalue); + color->setOpacity(qBound(0.0f, opacity, 1.0f)); updateRow(row); } - else - { - QMessageBox::warning(window, tr("Error"), tr("Please enter a percentage from 0% to 100%!")); - color_table->item(row, column)->setText(QString::number(color->getOpacity() * 100) + "%"); - } react_to_changes = true; } else @@ -385,6 +372,10 @@ void ColorWidget::addRow(int row) react_to_changes = true; + // Opacity + item = color_table->item(row, 6); + item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable); + updateRow(row); } @@ -418,7 +409,10 @@ void ColorWidget::updateRow(int row) item = color_table->item(row, 3); item->setToolTip(tr("Double click to define the color")); const MapColorCmyk& cmyk = color->getCmyk(); - item->setText(QString("%1/%2/%3/%4").arg(100*cmyk.c,0,'g',3).arg(100*cmyk.m,0,'g',3).arg(100*cmyk.y,0,'g',3).arg(100*cmyk.k,0,'g',3)); + QLocale l; + item->setText(QString::fromLatin1("%1/%2/%3/%4").arg( + l.toString(100*cmyk.c, 'g', 3), l.toString(100*cmyk.m, 'g', 3), + l.toString(100*cmyk.y, 'g', 3), l.toString(100*cmyk.k, 'g', 3))); switch (color->getCmykColorMethod()) { case MapColor::SpotColor: @@ -452,7 +446,9 @@ void ColorWidget::updateRow(int row) item->setCheckState(color->getKnockout() ? Qt::Checked : Qt::Unchecked); item->setForeground(palette().color(QPalette::Disabled, QPalette::Text)); -// color_table->item(row, 6)->setText(QString::number(color->getOpacity() * 100) + "%"); + // Opacity + item = color_table->item(row, 6); + item->setData(Qt::DisplayRole, color->getOpacity()); react_to_changes = true; } diff --git a/src/core/autosave.cpp b/src/core/autosave.cpp index d1755a4d9..0a2030365 100644 --- a/src/core/autosave.cpp +++ b/src/core/autosave.cpp @@ -119,7 +119,7 @@ Autosave::~Autosave() QString Autosave::autosavePath(const QString &path) const { - return path + ".autosave"; + return path + QLatin1String(".autosave"); } void Autosave::setAutosaveNeeded(bool needed) diff --git a/src/core/crs_template.cpp b/src/core/crs_template.cpp index 1995979c6..2299fb220 100644 --- a/src/core/crs_template.cpp +++ b/src/core/crs_template.cpp @@ -21,8 +21,6 @@ #include "crs_template.h" -#include - // From crs_template_implementation.h/.cpp namespace CRSTemplates @@ -89,7 +87,7 @@ QString CRSTemplate::coordinatesName(const std::vector& values) const key != last && value != last_value; ++key, ++value) { - name.replace(QLatin1String("@") % (*key)->id() % QLatin1String("@"), *value); + name.replace(QLatin1Char('@') + (*key)->id() + QLatin1Char('@'), *value); } return name; diff --git a/src/core/crs_template_implementation.cpp b/src/core/crs_template_implementation.cpp index c2d50d74e..811b52b3d 100644 --- a/src/core/crs_template_implementation.cpp +++ b/src/core/crs_template_implementation.cpp @@ -53,48 +53,48 @@ CRSTemplateRegistry::TemplateList defaultList() // UTM auto temp = make_unique( - "UTM", - Georeferencing::tr("UTM", "UTM coordinate reference system"), - Georeferencing::tr("UTM coordinates"), - "+proj=utm +datum=WGS84 +zone=%1", - CRSTemplate::ParameterList { - new UTMZoneParameter("zone", Georeferencing::tr("UTM Zone (number north/south)")) - } ); + QString::fromLatin1("UTM"), + Georeferencing::tr("UTM", "UTM coordinate reference system"), + Georeferencing::tr("UTM coordinates"), + QString::fromLatin1("+proj=utm +datum=WGS84 +zone=%1"), + CRSTemplate::ParameterList { + new UTMZoneParameter(QString::fromLatin1("zone"), Georeferencing::tr("UTM Zone (number north/south)")) + } ); templates.push_back(std::move(temp)); // Gauss-Krueger temp = make_unique( - "Gauss-Krueger, datum: Potsdam", - Georeferencing::tr("Gauss-Krueger, datum: Potsdam", "Gauss-Krueger coordinate reference system"), - Georeferencing::tr("Gauss-Krueger coordinates"), - "+proj=tmerc +lat_0=0 +lon_0=%1 +k=1.000000 +x_0=%2 +y_0=0 +ellps=bessel +datum=potsdam +units=m +no_defs", - CRSTemplate::ParameterList { - new IntRangeParameter("zone", Georeferencing::tr("Zone number (1 to 119)", "Zone number for Gauss-Krueger coordinates"), - 1, 119, { {3, 0}, {1000000, 500000} }) - } ); + QString::fromLatin1("Gauss-Krueger, datum: Potsdam"), + Georeferencing::tr("Gauss-Krueger, datum: Potsdam", "Gauss-Krueger coordinate reference system"), + Georeferencing::tr("Gauss-Krueger coordinates"), + QString::fromLatin1("+proj=tmerc +lat_0=0 +lon_0=%1 +k=1.000000 +x_0=%2 +y_0=0 +ellps=bessel +datum=potsdam +units=m +no_defs"), + CRSTemplate::ParameterList { + new IntRangeParameter(QString::fromLatin1("zone"), Georeferencing::tr("Zone number (1 to 119)", "Zone number for Gauss-Krueger coordinates"), + 1, 119, { {3, 0}, {1000000, 500000} }) + } ); templates.push_back(std::move(temp)); // EPSG temp = make_unique( - "EPSG", - Georeferencing::tr("by EPSG code", "as in: The CRS is specified by EPSG code"), - //: Don't translate @code@. It is placeholder. - Georeferencing::tr("EPSG @code@ coordinates"), - "+init=epsg:%1", - CRSTemplate::ParameterList { - new IntRangeParameter("code", Georeferencing::tr("EPSG code"), 1000, 99999) - } ); + QString::fromLatin1("EPSG"), + Georeferencing::tr("by EPSG code", "as in: The CRS is specified by EPSG code"), + //: Don't translate @code@. It is placeholder. + Georeferencing::tr("EPSG @code@ coordinates"), + QString::fromLatin1("+init=epsg:%1"), + CRSTemplate::ParameterList { + new IntRangeParameter(QString::fromLatin1("code"), Georeferencing::tr("EPSG code"), 1000, 99999) + } ); templates.push_back(std::move(temp)); // Custom temp = make_unique( - "PROJ.4", // Don't change this ID. - Georeferencing::tr("Custom PROJ.4", "PROJ.4 specification"), - Georeferencing::tr("Local coordinates"), - "%1", - CRSTemplate::ParameterList { - new FullSpecParameter("spec", Georeferencing::tr("Specification", "PROJ.4 specification")) - } ); + QString::fromLatin1("PROJ.4"), // Don't change this ID. + Georeferencing::tr("Custom PROJ.4", "PROJ.4 specification"), + Georeferencing::tr("Local coordinates"), + QString::fromLatin1("%1"), + CRSTemplate::ParameterList { + new FullSpecParameter(QString::fromLatin1("spec"), Georeferencing::tr("Specification", "PROJ.4 specification")) + } ); templates.push_back(std::move(temp)); return templates; @@ -187,8 +187,8 @@ QWidget* UTMZoneParameter::createEditor(WidgetObserver& observer) const std::vector UTMZoneParameter::specValues(const QString& edit_value) const { auto zone = QString { edit_value }; - zone.replace(" N", ""); - zone.replace(" S", " +south"); + zone.remove(QLatin1String(" N")); + zone.replace(QLatin1String(" S"), QLatin1String(" +south")); return { zone }; } @@ -223,8 +223,8 @@ QVariant UTMZoneParameter::calculateUTMZone(const LatLon lat_lon) zone_no = 2 * (int(floor(lon) + 3.0) / 12) + 31; // Svalbard QString zone = QString::number(zone_no); if (zone_no < 10) - zone.prepend('0'); - zone.append((lat >= 0.0) ? " N" : " S"); + zone.prepend(QLatin1Char('0')); + zone.append((lat >= 0.0) ? QLatin1String(" N") : QLatin1String(" S")); ret = zone; } diff --git a/src/core/georeferencing.cpp b/src/core/georeferencing.cpp index 3a0b22a33..286a43bd3 100644 --- a/src/core/georeferencing.cpp +++ b/src/core/georeferencing.cpp @@ -50,6 +50,7 @@ namespace literal static const QLatin1String georeferencing("georeferencing"); static const QLatin1String scale("scale"); + static const QLatin1String grid_scale_factor{"grid_scale_factor"}; static const QLatin1String declination("declination"); static const QLatin1String grivation("grivation"); @@ -121,19 +122,21 @@ namespace */ std::vector< std::pair > spec_substitutions { // #542, S-JTSK (Greenwich) / Krovak East North - { "+init=epsg:5514", "+proj=krovak +lat_0=49.5 +lon_0=24.83333333333333 +alpha=30.28813972222222 +k=0.9999 +x_0=0 +y_0=0 " - "+ellps=bessel +towgs84=542.5,89.2,456.9,5.517,2.275,5.516,6.96 +pm=greenwich +units=m +no_defs" }, + { QString::fromLatin1("+init=epsg:5514"), + QString::fromLatin1("+proj=krovak +lat_0=49.5 +lon_0=24.83333333333333 +alpha=30.28813972222222 +k=0.9999 +x_0=0 +y_0=0 " + "+ellps=bessel +towgs84=542.5,89.2,456.9,5.517,2.275,5.516,6.96 +pm=greenwich +units=m +no_defs") }, }; } //### Georeferencing ### -const QString Georeferencing::geographic_crs_spec("+proj=latlong +datum=WGS84"); +const QString Georeferencing::geographic_crs_spec(QString::fromLatin1("+proj=latlong +datum=WGS84")); Georeferencing::Georeferencing() : state(Local), scale_denominator(1), + grid_scale_factor{1.0}, declination(0.0), grivation(0.0), grivation_error(0.0), @@ -144,7 +147,7 @@ Georeferencing::Georeferencing() updateTransformation(); - projected_crs_id = "Local"; + projected_crs_id = QString::fromLatin1("Local"); projected_crs = NULL; geographic_crs = pj_init_plus_no_defs(geographic_crs_spec); Q_ASSERT(geographic_crs != NULL); @@ -154,6 +157,7 @@ Georeferencing::Georeferencing(const Georeferencing& other) : QObject(), state(other.state), scale_denominator(other.scale_denominator), + grid_scale_factor{other.grid_scale_factor}, declination(other.declination), grivation(other.grivation), grivation_error(other.grivation_error), @@ -183,6 +187,7 @@ Georeferencing& Georeferencing::operator=(const Georeferencing& other) { state = other.state; scale_denominator = other.scale_denominator; + grid_scale_factor = other.grid_scale_factor; declination = other.declination; grivation = other.grivation; grivation_error = other.grivation_error; @@ -223,6 +228,13 @@ void Georeferencing::load(QXmlStreamReader& xml, bool load_scale_only) if (scale_denominator <= 0) throw FileFormatException(tr("Map scale specification invalid or missing.")); + if (georef_element.hasAttribute(literal::grid_scale_factor)) + { + grid_scale_factor = roundScaleFactor(georef_element.attribute(literal::grid_scale_factor)); + if (grid_scale_factor <= 0.0) + throw FileFormatException(tr("Invalid grid scale factor: %1").arg(QString::number(grid_scale_factor))); + } + state = Local; if (load_scale_only) { @@ -337,6 +349,8 @@ void Georeferencing::save(QXmlStreamWriter& xml) const { XmlElementWriter georef_element(xml, literal::georeferencing); georef_element.writeAttribute(literal::scale, scale_denominator); + if (grid_scale_factor != 1.0) + georef_element.writeAttribute(literal::grid_scale_factor, grid_scale_factor, scaleFactorPrecision()); if (!qIsNull(declination)) georef_element.writeAttribute(literal::declination, declination, declinationPrecision()); if (!qIsNull(grivation)) @@ -412,7 +426,7 @@ void Georeferencing::setState(Georeferencing::State value) updateTransformation(); if (state != Normal) - setProjectedCRS("Local"); + setProjectedCRS(QString::fromLatin1("Local")); emit stateChanged(); } @@ -428,6 +442,16 @@ void Georeferencing::setScaleDenominator(int value) } } +void Georeferencing::setGridScaleFactor(double value) +{ + Q_ASSERT(value > 0); + if (grid_scale_factor != value) + { + grid_scale_factor = value; + updateTransformation(); + } +} + void Georeferencing::setDeclination(double value) { double declination = roundDeclination(value); @@ -564,7 +588,7 @@ void Georeferencing::updateTransformation() transform.translate(projected_ref_point.x(), projected_ref_point.y()); transform.rotate(-grivation); - double scale = double(scale_denominator) / 1000.0; + double scale = grid_scale_factor * scale_denominator / 1000.0; // to meters transform.scale(scale, -scale); transform.translate(-map_ref_point.x(), -map_ref_point.y()); @@ -596,7 +620,7 @@ void Georeferencing::setTransformationDirectly(const QTransform& transform) } } -bool Georeferencing::setProjectedCRS(const QString& id, QString spec, std::vector< QString > params) +bool Georeferencing::setProjectedCRS(const QString& id, QString spec, std::vector params) { // Default return value if no change is neccessary bool ok = (state == Normal || projected_crs_spec.isEmpty()); @@ -779,6 +803,7 @@ QDebug operator<<(QDebug dbg, const Georeferencing &georef) { dbg.nospace() << "Georeferencing(1:" << georef.scale_denominator + << " " << georef.grid_scale_factor << " " << georef.declination << " " << georef.grivation << "deg, " << georef.projected_crs_id @@ -817,9 +842,9 @@ extern "C" { if (temp_dir->isValid()) { - QString path = QDir(temp_dir->path()).filePath(name); + QString path = QDir(temp_dir->path()).filePath(QString::fromUtf8(name)); QFile file(path); - if (file.exists() || QFile::copy(QString("assets:/proj/") % QLatin1String(name), path)) + if (file.exists() || QFile::copy(QLatin1String("assets:/proj/") + QLatin1String(name), path)) { c_string = path.toLocal8Bit(); return c_string.constData(); diff --git a/src/core/georeferencing.h b/src/core/georeferencing.h index fa5c53930..6d9f07858 100644 --- a/src/core/georeferencing.h +++ b/src/core/georeferencing.h @@ -55,8 +55,8 @@ extern "C" void registerProjFileHelper(); * * Conversions between map coordinates and "projected coordinates" (flat metric * coordinates in a projected coordinate reference system) are made as affine - * transformation based on the map scale, the grivation and a defined - * reference point. + * transformation based on the map scale (principal scale), grid scale factor, + * the grivation and a defined reference point. * * Conversions between projected coordinates and geographic coordinates (here: * latitude/longitude for the WGS84 datum) are made based on a specification @@ -91,6 +91,22 @@ friend QDebug operator<<(QDebug dbg, const Georeferencing& georef); }; + /** + * @brief Returns the precision of the grid scale factor. + * + * The precision is given in number of decimal places, + * i.e. digits after the decimal point. + */ + static constexpr unsigned int scaleFactorPrecision(); + + /** + * @brief Rounds according to the defined precision of the grid scale factor. + * + * @see scaleFactorPrecision(); + */ + static double roundScaleFactor(double value); + + /** * @brief Returns the precision of declination/grivation/convergence. * @@ -99,7 +115,7 @@ friend QDebug operator<<(QDebug dbg, const Georeferencing& georef); * * All values set as declination or grivation will be rounded to this precisison. */ - static unsigned int declinationPrecision(); + static constexpr unsigned int declinationPrecision(); /** * @brief Rounds according to the defined precision of declination/grivation/convergence. @@ -183,16 +199,40 @@ friend QDebug operator<<(QDebug dbg, const Georeferencing& georef); /** - * Returns the map scale denominator. + * Returns the principal scale denominator. + * + * The principal scale - or representative fraction - is the ratio between + * units on the printed map and units on ground. */ unsigned int getScaleDenominator() const; /** - * Sets the map scale denominator. + * Sets the principal scale denominator. */ void setScaleDenominator(int value); + /** + * Returns the grid scale factor. + * + * The grid scale factor is the ratio between a length in the grid and the + * length on the earth model. It is applied as a factor to ground distances + * to get grid plane distances. + * + * Mapper doesn't explicitly deal with any other factors (elevation factor, + * unit of measurement). Technically, this property can be used as a + * combined factor. + */ + double getGridScaleFactor() const; + + /** + * Sets the grid scale factor. + * + * \see getGridScaleFactor() + */ + void setGridScaleFactor(double value); + + /** * Returns the magnetic declination (in degrees). * @@ -320,7 +360,7 @@ friend QDebug operator<<(QDebug dbg, const Georeferencing& georef); * @param params parameter values (ignore for empty spec) * @return true if the specification is valid or empty, false otherwise */ - bool setProjectedCRS(const QString& id, QString spec = QString::null, std::vector< QString > params = std::vector< QString >()); + bool setProjectedCRS(const QString& id, QString spec = QString{}, std::vector< QString > params = std::vector()); /** * Calculates the meridian convergence at the reference point. @@ -486,6 +526,7 @@ friend QDebug operator<<(QDebug dbg, const Georeferencing& georef); State state; unsigned int scale_denominator; + double grid_scale_factor; double declination; double grivation; double grivation_error; @@ -522,7 +563,20 @@ QDebug operator<<(QDebug dbg, const Georeferencing &georef); //### Georeferencing inline code ### inline -unsigned int Georeferencing::declinationPrecision() +constexpr unsigned int Georeferencing::scaleFactorPrecision() +{ + return 6u; +} + +inline +double Georeferencing::roundScaleFactor(double value) +{ + // This must match the implementation in scaleFactorPrecision(). + return floor(value*1000000.0+0.5)/1000000.0; +} + +inline +constexpr unsigned int Georeferencing::declinationPrecision() { // This must match the implementation in declinationRound(). return 2u; @@ -559,6 +613,12 @@ unsigned int Georeferencing::getScaleDenominator() const return scale_denominator; } +inline +double Georeferencing::getGridScaleFactor() const +{ + return grid_scale_factor; +} + inline double Georeferencing::getDeclination() const { diff --git a/src/core/map_color.cpp b/src/core/map_color.cpp index 4e62d5857..738b7245e 100644 --- a/src/core/map_color.cpp +++ b/src/core/map_color.cpp @@ -21,11 +21,11 @@ #include "map_color.h" -#include +#include MapColor::MapColor() -: name(QApplication::translate("Map", "New color")), +: name(QCoreApplication::translate("Map", "New color")), priority(Undefined), opacity(1.0f), q_color(Qt::black), @@ -39,7 +39,7 @@ MapColor::MapColor() } MapColor::MapColor(int priority) -: name(QApplication::translate("Map", "New color")), +: name(QCoreApplication::translate("Map", "New color")), priority(priority), opacity(1.0f), q_color(Qt::black), @@ -68,7 +68,7 @@ MapColor::MapColor(int priority) break; case Registration: Q_ASSERT(isBlack()); - name = QApplication::translate("MapColor", "Registration black (all printed colors)"); + name = QCoreApplication::translate("MapColor", "Registration black (all printed colors)"); break; default: ; // no change @@ -84,7 +84,7 @@ MapColor::MapColor(const QString& name, int priority) cmyk_color_method(MapColor::CustomColor), rgb_color_method(MapColor::CmykColor), flags(0), - spot_color_name("") + spot_color_name() { Q_ASSERT(isBlack()); } @@ -302,9 +302,8 @@ void MapColor::updateCompositionName() { if (!spot_color_name.isEmpty()) spot_color_name += QLatin1String(", "); - spot_color_name += QString("%1 %2%").arg( - component.spot_color->getSpotColorName(), - QString::number(component.factor * 100) /* % */); + spot_color_name += component.spot_color->getSpotColorName() + QLatin1Char(' ') + + QString::number(component.factor * 100) /* % */; } } } diff --git a/src/core/map_coord.cpp b/src/core/map_coord.cpp index 9d035512b..b23d2d2ad 100644 --- a/src/core/map_coord.cpp +++ b/src/core/map_coord.cpp @@ -30,6 +30,9 @@ #include "../util/xml_stream_util.h" +static_assert(sizeof(qint32) <= sizeof(int), + "MapCoord::setX/Y uses qRound() returning int, xp/yp is of type qint32"); + static_assert(!MapCoord::BoundsOffset().check_for_offset, "Default-constructed BoundsOffset must have check_for_offset == false."); static_assert(MapCoord::BoundsOffset().x == 0, @@ -254,14 +257,18 @@ QString MapCoord::toString() const * 3 * Total: 28 */ constexpr std::size_t buf_size = 1+2+2+20+3; - static QChar encoded[10] = { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' + static const QChar encoded[10] = { + QLatin1Char{'0'}, QLatin1Char{'1'}, + QLatin1Char{'2'}, QLatin1Char{'3'}, + QLatin1Char{'4'}, QLatin1Char{'5'}, + QLatin1Char{'6'}, QLatin1Char{'7'}, + QLatin1Char{'8'}, QLatin1Char{'9'} }; QChar buffer[buf_size]; // For efficiency, we construct the string from the back. std::size_t j = buf_size - 1; - buffer[j] = QChar{ ';' }; + buffer[j] = QLatin1Char{';'}; --j; int flags = fp; @@ -286,7 +293,7 @@ QString MapCoord::toString() const QChar sign { QChar::Null }; if (tmp < 0) { - sign = QChar{ '-' }; + sign = QLatin1Char{'-'}; tmp = -tmp; } do @@ -312,7 +319,7 @@ QString MapCoord::toString() const tmp = xp; if (tmp < 0) { - sign = QChar{ '-' }; + sign = QLatin1Char{'-'}; tmp = -tmp; } do @@ -334,27 +341,99 @@ QString MapCoord::toString() const return QString(buffer+j, buf_size-j); } - - -QTextStream& operator>>(QTextStream& stream, MapCoord& coord) +MapCoord::MapCoord(QStringRef& text) +: MapCoord{} { - // Always update all MapCoord members here (xp, yp, flags). - qint64 x64, y64; - QChar separator; - stream >> x64 >> y64 >> separator; + const int len = text.length(); + if (Q_UNLIKELY(len < 2)) + throw std::invalid_argument("Premature end of data"); - handleBoundsOffset(x64, y64); - ensureBoundsForQint32(x64, y64); + auto data = text.constData(); + int i = 0; + + qint64 x64 = data[0].unicode(); + if (x64 == '-') + { + x64 = '0' - data[1].unicode(); + for (i = 2; i != len; ++i) + { + auto c = data[i].unicode(); + if (c < '0' || c > '9') + break; + else + x64 = 10*x64 + '0' - c; + } + } + else if (x64 >= '0' && x64 <= '9') + { + x64 -= '0'; + for (i = 1; i != len; ++i) + { + auto c = data[i].unicode(); + if (c < '0' || c > '9') + break; + else + x64 = 10*x64 + c - '0'; + } + } - coord.xp = static_cast(x64); - coord.yp = static_cast(y64); + ++i; + if (Q_UNLIKELY(i+1 >= len)) + throw std::invalid_argument("Premature end of data"); - int flags = 0; - if (separator == QChar::Space) + qint64 y64 = data[i].unicode(); + if (y64 == '-') { - stream >> flags >> separator; + ++i; + y64 = '0' - data[i].unicode(); + for (++i; i != len; ++i) + { + auto c = data[i].unicode(); + if (c < '0' || c > '9') + break; + else + y64 = 10*y64 + '0' - c; + } + } + else if (y64 >= '0' && y64 <= '9') + { + y64 -= '0'; + for (++i; i != len; ++i) + { + auto c = data[i].unicode(); + if (c < '0' || c > '9') + break; + else + y64 = 10*y64 + c - '0'; + } + } + + handleBoundsOffset(y64, y64); + ensureBoundsForQint32(y64, y64); + xp = static_cast(x64); + yp = static_cast(y64); + + if (i < len && data[i] == QChar::Space) + { + ++i; + if (Q_UNLIKELY(i == len)) + throw std::invalid_argument("Premature end of data"); + + // there are no negative flags + fp = Flags(data[i].unicode() - '0'); + for (++i; i < len; ++i) + { + auto c = data[i].unicode(); + if (c < '0' || c > '9') + break; + else + fp = Flags(10*int(fp) + c - '0'); + } } - coord.setFlags(flags); - return stream; + if (Q_UNLIKELY(i >= len || data[i] != QLatin1Char{';'})) + throw std::invalid_argument("Invalid data"); + + ++i; + text = text.mid(i, len-i); } diff --git a/src/core/map_coord.h b/src/core/map_coord.h index a7b5d3698..a1eafe9f7 100644 --- a/src/core/map_coord.h +++ b/src/core/map_coord.h @@ -381,6 +381,20 @@ class MapCoord */ QString toString() const; + /** + * Constructs the MapCoord from the beginning of text, and moves the + * reference to behind the this coordinates data. + * + * This is the counterpiece to toString(). It will throw a + * std::invalid_argument if the (beginning of) text does not + * contain valid data. + * + * This constructor will initialize the boundsOffset() if neccessary. + * Otherwise it will apply the BoundsOffset() and throw a std::range_error + * if the adjusted coordinates are out of bounds for qint32. + */ + MapCoord(QStringRef& text); + /** Saves the MapCoord in xml format to the stream. */ void save(QXmlStreamWriter& xml) const; @@ -402,7 +416,6 @@ class MapCoord friend constexpr MapCoord operator*(const MapCoord& lhs, qreal factor); friend constexpr MapCoord operator*(qreal factor, const MapCoord& rhs); friend constexpr MapCoord operator/(const MapCoord& lhs, qreal divisor); - friend QTextStream& operator>>(QTextStream& stream, MapCoord& coord); }; /** Compare MapCoord for equality. */ @@ -434,18 +447,6 @@ constexpr MapCoord operator*(qreal factor, const MapCoord& rhs); constexpr MapCoord operator/(const MapCoord& lhs, qreal divisor); -/** - * Reads raw coordinates and flags from a text stream. - * - * This will initialize the boundsOffset() if neccessary. Otherwise it will - * apply the BoundsOffset() and throw a std::range_error if the adjusted - * coordinates are out of bounds for qint32. - * - * @see MapCoord::toString() - */ -QTextStream& operator>>(QTextStream& stream, MapCoord& coord); - - /** * Map coordinates stored as floating point numbers. @@ -707,13 +708,13 @@ constexpr qreal MapCoord::y() const inline void MapCoord::setX(qreal x) { - this->xp = qRound64(x * 1000); + this->xp = qRound(x * 1000); } inline void MapCoord::setY(qreal y) { - this->yp = qRound64(y * 1000); + this->yp = qRound(y * 1000); } constexpr qint32 MapCoord::nativeX() const diff --git a/src/core/map_grid.cpp b/src/core/map_grid.cpp index b077110ef..3d0bf44de 100644 --- a/src/core/map_grid.cpp +++ b/src/core/map_grid.cpp @@ -32,6 +32,7 @@ #include "../map.h" #include "../core/map_coord.h" #include "../util.h" +#include "../util/xml_stream_util.h" struct ProcessLine { @@ -89,35 +90,35 @@ const MapGrid& MapGrid::load(QIODevice* file, int version) void MapGrid::save(QXmlStreamWriter& xml) const { - xml.writeEmptyElement("grid"); - xml.writeAttribute("color", QColor(color).name()); - xml.writeAttribute("display", QString::number(display)); - xml.writeAttribute("alignment", QString::number(alignment)); - xml.writeAttribute("additional_rotation", QString::number(additional_rotation)); - xml.writeAttribute("unit", QString::number(unit)); - xml.writeAttribute("h_spacing", QString::number(horz_spacing)); - xml.writeAttribute("v_spacing", QString::number(vert_spacing)); - xml.writeAttribute("h_offset", QString::number(horz_offset)); - xml.writeAttribute("v_offset", QString::number(vert_offset)); - xml.writeAttribute("snapping_enabled", snapping_enabled ? "true" : "false"); + XmlElementWriter element{xml, QLatin1String("grid")}; + element.writeAttribute(QLatin1String("color"), QColor(color).name()); + element.writeAttribute(QLatin1String("display"), display); + element.writeAttribute(QLatin1String("alignment"), alignment); + element.writeAttribute(QLatin1String("additional_rotation"), additional_rotation); + element.writeAttribute(QLatin1String("unit"), unit); + element.writeAttribute(QLatin1String("h_spacing"), horz_spacing); + element.writeAttribute(QLatin1String("v_spacing"), vert_spacing); + element.writeAttribute(QLatin1String("h_offset"), horz_offset); + element.writeAttribute(QLatin1String("v_offset"), vert_offset); + element.writeAttribute(QLatin1String("snapping_enabled"), snapping_enabled); } const MapGrid& MapGrid::load(QXmlStreamReader& xml) { - Q_ASSERT(xml.name() == "grid"); + Q_ASSERT(xml.name() == QLatin1String("grid")); + XmlElementReader element(xml); QXmlStreamAttributes attributes = xml.attributes(); - color = QColor(attributes.value("color").toString()).rgba(); - display = (MapGrid::DisplayMode) attributes.value("display").toString().toInt(); - alignment = (MapGrid::Alignment) attributes.value("alignment").toString().toInt(); - additional_rotation = attributes.value("additional_rotation").toString().toDouble(); - unit = (MapGrid::Unit) attributes.value("unit").toString().toInt(); - horz_spacing = attributes.value("h_spacing").toString().toDouble(); - vert_spacing = attributes.value("v_spacing").toString().toDouble(); - horz_offset = attributes.value("h_offset").toString().toDouble(); - vert_offset = attributes.value("v_offset").toString().toDouble(); - snapping_enabled = (attributes.value("snapping_enabled") == "true"); - xml.skipCurrentElement(); + color = QColor(element.attribute(QLatin1String("color"))).rgba(); + display = MapGrid::DisplayMode(element.attribute(QLatin1String("display"))); + alignment = MapGrid::Alignment(element.attribute(QLatin1String("alignment"))); + additional_rotation = element.attribute(QLatin1String("additional_rotation")); + unit = MapGrid::Unit(element.attribute(QLatin1String("unit"))); + horz_spacing = element.attribute(QLatin1String("h_spacing")); + vert_spacing = element.attribute(QLatin1String("v_spacing")); + horz_offset = element.attribute(QLatin1String("h_offset")); + vert_offset = element.attribute(QLatin1String("v_offset")); + snapping_enabled = element.attribute(QLatin1String("snapping_enabled")); return *this; } diff --git a/src/core/map_printer.cpp b/src/core/map_printer.cpp index ff91cf8b7..d3de2a414 100644 --- a/src/core/map_printer.cpp +++ b/src/core/map_printer.cpp @@ -1,6 +1,6 @@ /* * Copyright 2012, 2013 Thomas Schöps - * Copyright 2012-2015 Kai Pastor + * Copyright 2012-2016 Kai Pastor * * This file is part of OpenOrienteering. * @@ -34,11 +34,13 @@ #if defined(QT_PRINTSUPPORT_LIB) # include +# include # if defined(Q_OS_WIN) # include # endif #endif +#include "../core/georeferencing.h" #include "../core/map_color.h" #include "../core/map_view.h" #include "../map.h" @@ -140,7 +142,7 @@ bool operator==(const MapPrinterPageFormat& lhs, const MapPrinterPageFormat& rhs // ### MapPrinterOptions ### -MapPrinterOptions::MapPrinterOptions(unsigned int scale, unsigned int resolution, MapPrinterMode mode) +MapPrinterOptions::MapPrinterOptions(unsigned int scale, int resolution, MapPrinterMode mode) : scale(scale), resolution(resolution), mode(mode), @@ -157,25 +159,19 @@ MapPrinterOptions::MapPrinterOptions(unsigned int scale, unsigned int resolution // ### MapPrinterConfig ### MapPrinterConfig::MapPrinterConfig(const Map& map) - : printer_name("DEFAULT"), + : printer_name(QString::fromLatin1("DEFAULT")), print_area(map.calculateExtent()), page_format(MapPrinterPageFormat::fromDefaultPrinter()), options(map.getScaleDenominator()), center_print_area(false), single_page_print_area(false) { - options.resolution = 600.0; - options.scale = map.getScaleDenominator(); - options.show_grid = false; - options.show_templates = false; - options.simulate_overprinting = false; - if (print_area.isEmpty()) print_area = page_format.page_rect; } MapPrinterConfig::MapPrinterConfig(const Map& map, QXmlStreamReader& xml) - : printer_name("DEFAULT"), + : printer_name(QString::fromLatin1("DEFAULT")), print_area(0.0, 0.0, 100.0, 100.0), // Avoid expensive calculation before loading. page_format(), options(map.getScaleDenominator()), @@ -185,7 +181,7 @@ MapPrinterConfig::MapPrinterConfig(const Map& map, QXmlStreamReader& xml) XmlElementReader printer_config_element(xml); options.scale = printer_config_element.attribute(literal::scale); - options.resolution = printer_config_element.attribute(literal::resolution); + options.resolution = printer_config_element.attribute(literal::resolution); options.show_templates = printer_config_element.attribute(literal::templates_visible); options.show_grid = printer_config_element.attribute(literal::grid_visible); options.simulate_overprinting = printer_config_element.attribute(literal::simulate_overprinting); @@ -224,7 +220,7 @@ MapPrinterConfig::MapPrinterConfig(const Map& map, QXmlStreamReader& xml) const QHash< int, const char* >& paper_size_names = MapPrinter::paperSizeNames(); for (int i = 0; i < paper_size_names.count(); ++i) { - if (value == paper_size_names[i]) + if (value == QLatin1String(paper_size_names[i])) page_format.paper_size = i; } #endif @@ -291,7 +287,7 @@ void MapPrinterConfig::save(QXmlStreamWriter& xml, const QLatin1String& element_ break; default: // Do not fail on saving - qDebug() << "Unsupported map printig mode:" << options.mode; + qDebug() << "Unsupported map printing mode:" << options.mode; } switch (options.color_mode) @@ -398,8 +394,9 @@ MapPrinter::MapPrinter(Map& map, const MapView* view, QObject* parent) view(view), target(nullptr) { - scale_adjustment = map.getScaleDenominator() / (qreal) options.scale; + scale_adjustment = map.getScaleDenominator() / qreal(options.scale); updatePaperDimensions(); + connect(&map.getGeoreferencing(), &Georeferencing::transformationChanged, this, &MapPrinter::mapScaleChanged); } MapPrinter::~MapPrinter() @@ -473,6 +470,13 @@ std::unique_ptr MapPrinter::makePrinter() const return printer; } + // Color can only be changed in (native) properties dialogs. This is the default. + printer->setColorMode(separationsModeSelected() ? QPrinter::GrayScale : QPrinter::Color); + if (printer->outputFormat() == QPrinter::NativeFormat) + { + PlatformPrinterProperties::restore(printer.get(), native_data); + } + printer->setDocName(tr("- Map -")); printer->setFullPage(true); if (page_format.paper_size == QPrinter::Custom) @@ -482,10 +486,9 @@ std::unique_ptr MapPrinter::makePrinter() const } else { - printer->setPaperSize((QPrinter::PaperSize)page_format.paper_size); + printer->setPaperSize(QPrinter::PaperSize(page_format.paper_size)); printer->setOrientation((page_format.orientation == MapPrinterPageFormat::Portrait) ? QPrinter::Portrait : QPrinter::Landscape); } - printer->setColorMode(separationsModeSelected() ? QPrinter::GrayScale : QPrinter::Color); printer->setResolution(options.resolution); if (page_format.paper_size == QPrinter::Custom || !isPrinter()) @@ -582,8 +585,8 @@ void MapPrinter::setOverlap(qreal h_overlap, qreal v_overlap) { if (page_format.h_overlap != h_overlap || page_format.v_overlap != v_overlap) { - page_format.h_overlap = qMax((qreal)0.0, qMin(h_overlap, page_format.page_rect.width())); - page_format.v_overlap = qMax((qreal)0.0, qMin(v_overlap, page_format.page_rect.height())); + page_format.h_overlap = qMax(qreal(0), qMin(h_overlap, page_format.page_rect.width())); + page_format.v_overlap = qMax(qreal(0), qMin(v_overlap, page_format.page_rect.height())); updatePageBreaks(); emit pageFormatChanged(page_format); } @@ -595,15 +598,15 @@ void MapPrinter::updatePaperDimensions() { // No margins, no need to query QPrinter. page_format.page_rect = QRectF(QPointF(0.0, 0.0), page_format.paper_dimensions); - page_format.h_overlap = qMax((qreal)0.0, qMin(page_format.h_overlap, page_format.page_rect.width())); - page_format.v_overlap = qMax((qreal)0.0, qMin(page_format.v_overlap, page_format.page_rect.height())); + page_format.h_overlap = qMax(qreal(0), qMin(page_format.h_overlap, page_format.page_rect.width())); + page_format.v_overlap = qMax(qreal(0), qMin(page_format.v_overlap, page_format.page_rect.height())); updatePageBreaks(); return; } QPrinter* printer = target ? new QPrinter(*target, QPrinter::HighResolution) : new QPrinter(QPrinter::HighResolution); - if (!printer->isValid()) + if (!printer->isValid() || target == imageTarget() || target == pdfTarget()) printer->setOutputFormat(QPrinter::PdfFormat); if (page_format.paper_size == QPrinter::Custom) @@ -613,7 +616,7 @@ void MapPrinter::updatePaperDimensions() } else { - printer->setPaperSize((QPrinter::PaperSize)page_format.paper_size); + printer->setPaperSize(QPrinter::PaperSize(page_format.paper_size)); printer->setOrientation((page_format.orientation == MapPrinterPageFormat::Portrait) ? QPrinter::Portrait : QPrinter::Landscape); } @@ -627,15 +630,15 @@ void MapPrinter::updatePaperDimensions() printer->getPageMargins(&left, &top, &right, &bottom, QPrinter::Millimeter); page_format.page_rect.adjust(left, top, -right, -bottom); } - page_format.h_overlap = qMax((qreal)0.0, qMin(page_format.h_overlap, page_format.page_rect.width())); - page_format.v_overlap = qMax((qreal)0.0, qMin(page_format.v_overlap, page_format.page_rect.height())); + page_format.h_overlap = qMax(qreal(0), qMin(page_format.h_overlap, page_format.page_rect.width())); + page_format.v_overlap = qMax(qreal(0), qMin(page_format.v_overlap, page_format.page_rect.height())); delete printer; updatePageBreaks(); } // slot -void MapPrinter::setResolution(const unsigned int dpi) +void MapPrinter::setResolution(int dpi) { if (dpi > 0 && options.resolution != dpi) { @@ -651,7 +654,7 @@ void MapPrinter::setScale(const unsigned int value) { Q_ASSERT(value > 0); options.scale = value; - scale_adjustment = map.getScaleDenominator() / (qreal) value; + scale_adjustment = map.getScaleDenominator() / qreal(value); updatePageBreaks(); emit optionsChanged(options); } @@ -765,6 +768,17 @@ void MapPrinter::updatePageBreaks() } } +void MapPrinter::mapScaleChanged() +{ + auto value = qreal(map.getScaleDenominator()) / options.scale; + if (!qFuzzyCompare(scale_adjustment, value)) + { + scale_adjustment = value; + updatePageBreaks(); + emit optionsChanged(options); + } +} + void MapPrinter::takePrinterSettings(const QPrinter* printer) { MapPrinterPageFormat f(*printer); @@ -784,6 +798,11 @@ void MapPrinter::takePrinterSettings(const QPrinter* printer) } setResolution(printer->resolution()); + + if (printer && printer->outputFormat() == QPrinter::NativeFormat) + { + PlatformPrinterProperties::save(printer, native_data); + } } // local @@ -1135,7 +1154,7 @@ bool MapPrinter::printMap(QPrinter* printer) QSizeF extent_size = page_format.page_rect.size() / scale_adjustment; QPainter painter(printer); - float resolution = (float)options.resolution; + auto resolution = float(options.resolution); #if defined(Q_OS_WIN) // Workaround for Wine @@ -1192,7 +1211,7 @@ bool MapPrinter::printMap(QPrinter* printer) cancel_print_map = false; int step = 0; - int num_steps = v_page_pos.size() * h_page_pos.size(); + auto num_steps = v_page_pos.size() * h_page_pos.size(); const QString message_template( (options.mode == MapPrinterOptions::Separations) ? tr("Processing separations of page %1...") : tr("Processing page %1...") ); @@ -1215,7 +1234,7 @@ bool MapPrinter::printMap(QPrinter* printer) } ++step; - int progress = qMin(99, qMax(1, (100*step-50)/num_steps)); + auto progress = qMin(99, qMax(1, int((100 * static_cast(step) - 50) / num_steps))); emit printProgress(progress, message_template.arg(step)); if (cancel_print_map) /* during printProgress handling */ @@ -1264,4 +1283,4 @@ void MapPrinter::cancelPrintMap() cancel_print_map = true; } -#endif +#endif // QT_PRINTSUPPORT_LIB diff --git a/src/core/map_printer.h b/src/core/map_printer.h index d4b939ebf..c7f8cdc06 100644 --- a/src/core/map_printer.h +++ b/src/core/map_printer.h @@ -1,6 +1,6 @@ /* * Copyright 2012, 2013 Thomas Schöps - * Copyright 2012-2015 Kai Pastor + * Copyright 2012-2016 Kai Pastor * * This file is part of OpenOrienteering. * @@ -121,13 +121,13 @@ class MapPrinterOptions * The scale, the mode and the resolution are initialized to the given * values, all boolean properties are initialized to false. */ - MapPrinterOptions(unsigned int scale, unsigned int resolution = 600, MapPrinterMode mode = Vector); + MapPrinterOptions(unsigned int scale, int resolution = 600, MapPrinterMode mode = Vector); /** The scale to be used for printing. */ unsigned int scale; /** The nominal resolution to be used. */ - unsigned int resolution; + int resolution; /** The mode of printing. * @@ -192,6 +192,9 @@ class MapPrinterConfig /** A flag which indicates to the UI whether to adjust the print area size * to the current page size. */ bool single_page_print_area; + + /** Platform-dependent data. */ + std::shared_ptr native_data; }; @@ -310,9 +313,9 @@ public slots: /** Sets the desired printing resolution in dpi. * The actual resolution will be set by the printer. * - * Does nothing if dpi is 0. + * Does nothing if dpi is 0 or less. */ - void setResolution(const unsigned int dpi); + void setResolution(int dpi); /** Sets the denominator of the map scale for printing. */ void setScale(const unsigned int value); @@ -379,6 +382,9 @@ public slots: /** Updates the page breaks from map area and page format. */ void updatePageBreaks(); + /** Updates the scale adjustment and page breaks. */ + void mapScaleChanged(); + Map& map; const MapView* view; const QPrinterInfo* target; diff --git a/src/core/map_view.cpp b/src/core/map_view.cpp index 3d12ea606..07afa5822 100644 --- a/src/core/map_view.cpp +++ b/src/core/map_view.cpp @@ -1,6 +1,6 @@ /* * Copyright 2012, 2013 Thomas Schöps - * Copyright 2014, 2015 Kai Pastor + * Copyright 2014-2016 Kai Pastor * * This file is part of OpenOrienteering. * @@ -122,7 +122,7 @@ void MapView::load(QIODevice* file, int version) #endif -void MapView::save(QXmlStreamWriter& xml, const QLatin1String& element_name, bool skip_templates) +void MapView::save(QXmlStreamWriter& xml, const QLatin1String& element_name) const { XmlElementWriter mapview_element(xml, element_name); mapview_element.writeAttribute(literal::zoom, zoom); @@ -139,20 +139,16 @@ void MapView::save(QXmlStreamWriter& xml, const QLatin1String& element_name, boo } { - if (!skip_templates) + XmlElementWriter templates_element(xml, literal::templates); + templates_element.writeAttribute(literal::hidden, all_templates_hidden); + templates_element.writeAttribute(XmlStreamLiteral::count, template_visibilities.size()); + + for (auto it = template_visibilities.constBegin(), last = template_visibilities.constEnd(); it != last; ++it) { - XmlElementWriter templates_element(xml, literal::templates); - templates_element.writeAttribute(literal::hidden, all_templates_hidden); - templates_element.writeAttribute(XmlStreamLiteral::count, template_visibilities.size()); - - QHash::const_iterator it = template_visibilities.constBegin(); - for ( ; it != template_visibilities.constEnd(); ++it) - { - XmlElementWriter ref_element(xml, literal::ref); - ref_element.writeAttribute(literal::template_string, map->findTemplateIndex(it.key())); - ref_element.writeAttribute(literal::visible, (*it)->visible); - ref_element.writeAttribute(literal::opacity, (*it)->opacity); - } + XmlElementWriter ref_element(xml, literal::ref); + ref_element.writeAttribute(literal::template_string, map->findTemplateIndex(it.key())); + ref_element.writeAttribute(literal::visible, (*it)->visible); + ref_element.writeAttribute(literal::opacity, (*it)->opacity); } } } diff --git a/src/core/map_view.h b/src/core/map_view.h index 065f63f2f..0259b8945 100644 --- a/src/core/map_view.h +++ b/src/core/map_view.h @@ -1,6 +1,6 @@ /* * Copyright 2012, 2013 Thomas Schöps - * Copyright 2014, 2015 Kai Pastor + * Copyright 2014-2016 Kai Pastor * * This file is part of OpenOrienteering. * @@ -70,9 +70,8 @@ class MapView /** Saves the map view state to an XML stream. * @param xml The XML output stream. * @param element_name The name of the element which will be written. - * @param skip_templates If true, visibility details of individual templates are not saved. */ - void save(QXmlStreamWriter& xml, const QLatin1String& element_name, bool skip_templates = false); + void save(QXmlStreamWriter& xml, const QLatin1String& element_name) const; /** Loads the map view state from the current element of an xml stream. */ void load(QXmlStreamReader& xml); diff --git a/src/core/path_coord.cpp b/src/core/path_coord.cpp index 87e65037f..5fe1a8160 100644 --- a/src/core/path_coord.cpp +++ b/src/core/path_coord.cpp @@ -1,6 +1,6 @@ /* * Copyright 2012, 2013 Thomas Schöps - * Copyright 2012-2015 Kai Pastor + * Copyright 2012-2016 Kai Pastor * * This file is part of OpenOrienteering. * @@ -124,7 +124,7 @@ MapCoordF SplitPathCoord::tangentVector() const goto next_found; } - if (flags[path_coords[index].index].isCurveStart()) + if (flags[index].isCurveStart()) { next = coords[index+1]; if (pos.distanceSquaredTo(next) >= PathCoord::tangentEpsilonSquared()) @@ -132,8 +132,8 @@ MapCoordF SplitPathCoord::tangentVector() const } // Search along curve - Q_ASSERT(index = path_coords[path_coord_index].index); - Q_ASSERT(index >= path_coords[index].index); + Q_ASSERT(index == path_coords[path_coord_index].index); + // Attention, switching from MapCoordVectorF index to PathCoordVector index. auto pc = std::lower_bound(std::begin(path_coords), std::begin(path_coords)+path_coord_index, index, PathCoord::indexLessThanValue); index = std::distance(std::begin(path_coords), pc); @@ -208,7 +208,6 @@ MapCoordF SplitPathCoord::tangentVector() const // Search along curve Q_ASSERT(index > path_coords[path_coord_index].index); - Q_ASSERT(index >= path_coords[index].index); // Attention, switching from MapCoordVectorF index to PathCoordVector index. index = std::upper_bound(std::begin(path_coords)+path_coord_index, std::end(path_coords)-1, index, PathCoord::valueLessThanIndex)->index; last_index = path_coord_index + 1; diff --git a/src/dxfparser.cpp b/src/dxfparser.cpp index fe4270daa..188677bd8 100644 --- a/src/dxfparser.cpp +++ b/src/dxfparser.cpp @@ -46,7 +46,7 @@ QString DXFParser::parse() buffer.open(QIODevice::ReadOnly); readNextCodeValue(&buffer, code, value); buffer.close(); - if (code != 0 || value != "SECTION") + if (code != 0 || value != QLatin1String("SECTION")) { // File does not start with DXF section return QApplication::translate("DXFParser", "The file is not an DXF file."); @@ -66,56 +66,56 @@ QString DXFParser::parse() */ while (readNextCodeValue(device, code, value)) { - if (code == 0 && value == "ENDSEC") + if (code == 0 && value == QLatin1String("ENDSEC")) { current_section = NOTHING; } - else if (code == 0 && value == "EOF") + else if (code == 0 && value == QLatin1String("EOF")) { current_section = NOTHING; } else if (current_section == NOTHING) { - if (code == 0 && value == "SECTION") + if (code == 0 && value == QLatin1String("SECTION")) { current_section = SECTION; } - else if (value == "EOF") + else if (value == QLatin1String("EOF")) { break; } } else if (current_section == SECTION) { - if (code == 2 && value == "ENTITIES") + if (code == 2 && value == QLatin1String("ENTITIES")) { current_section = ENTITIES; } - if (code == 2 && value == "HEADER") + if (code == 2 && value == QLatin1String("HEADER")) { current_section = HEADER; } } else if (current_section == ENTITIES) { - if (code == 0 && value == "LINE") + if (code == 0 && value == QLatin1String("LINE")) parseLine(device, &paths); - else if (code == 0 && value == "POLYLINE") + else if (code == 0 && value == QLatin1String("POLYLINE")) { parsePolyline(device, &paths); current_section = POLYLINE; } - else if (code == 0 && value == "LWPOLYLINE") + else if (code == 0 && value == QLatin1String("LWPOLYLINE")) parseLwPolyline(device, &paths); - else if (code == 0 && value == "SPLINE") + else if (code == 0 && value == QLatin1String("SPLINE")) parseSpline(device, &paths); - else if (code == 0 && value == "CIRCLE") + else if (code == 0 && value == QLatin1String("CIRCLE")) parseCircle(device, &paths); - else if (code == 0 && value == "POINT") + else if (code == 0 && value == QLatin1String("POINT")) parsePoint(device, &paths); - else if (code == 0 && value == "TEXT") + else if (code == 0 && value == QLatin1String("TEXT")) parseText(device, &paths); - else if (code == 0 && value == "ARC") + else if (code == 0 && value == QLatin1String("ARC")) parseArc(device, &paths); #if defined(MAPPER_DEVELOPMENT_BUILD) else if (code == 0) @@ -124,19 +124,19 @@ QString DXFParser::parse() } else if (current_section == HEADER) { - if (code == 9 && value == "$EXTMIN") + if (code == 9 && value == QLatin1String("$EXTMIN")) parseExtminmax(device, bottom_right); - else if (code == 9 && value == "$EXTMAX") + else if (code == 9 && value == QLatin1String("$EXTMAX")) parseExtminmax(device, top_left); } else if (current_section == POLYLINE) { - if (code == 0 && value == "SEQEND") + if (code == 0 && value == QLatin1String("SEQEND")) { parseSeqend(device, &paths); current_section = ENTITIES; } - else if (code == 0 && value == "VERTEX") + else if (code == 0 && value == QLatin1String("VERTEX")) parseVertex(device, &paths); } } @@ -164,7 +164,7 @@ inline bool DXFParser::readNextCodeValue(QIODevice *device, int &code, QString &value) { code = device->readLine(128).trimmed().toInt(); - value = device->readLine(256).trimmed(); + value = QString::fromUtf8(device->readLine(256).trimmed()); return !device->atEnd(); } @@ -309,9 +309,9 @@ void DXFParser::parseSpline(QIODevice* d, QList* p) { if (code == 71) { - if (value != "3") + if (value != QLatin1String("3")) { - qWarning() << QString("DXFParser: Splines of degree %1 are not supported!").arg(value); + qWarning() << "DXFParser: Splines of degree" << value << "are not supported!"; return; } } @@ -457,7 +457,7 @@ void DXFParser::parseText(QIODevice *d, QList *p) DXFPath path(TEXT); path.color = Qt::red; - path.text = ""; + path.text = QString::fromLatin1(""); DXFCoordinate co; int alignment = 0; int valignment = 0; @@ -477,9 +477,9 @@ void DXFParser::parseText(QIODevice *d, QList *p) else if (code == 50) path.rotation = value.toDouble(); else if (code == 1) - path.text = path.text.insert(path.text.indexOf(">")+1, value); + path.text = path.text.insert(path.text.indexOf(QLatin1Char('>'))+1, value); else if (code == 7) - path.text = path.text.arg(QString("font-family:")+value+QString(";%1")); + path.text = path.text.arg(QLatin1String("font-family:") + value + QLatin1String(";%1")); else if (code == 40) path.font.setPointSizeF(value.toDouble()); else if (code == 72) @@ -492,40 +492,40 @@ void DXFParser::parseText(QIODevice *d, QList *p) if (path.color != QColor(127,127,127)) { - path.text = path.text.arg(QString("color:")+path.color.name()+QString(";%1")); + path.text = path.text.arg(QLatin1String("color:") + path.color.name() + QLatin1String(";%1")); } - if (!path.text.contains("color")) + if (!path.text.contains(QLatin1String("color"))) { - path.text = path.text.arg("color:red"); + path.text = path.text.arg(QString::fromLatin1("color:red")); } switch(alignment) { case 0: - path.text = path.text.arg(QString("text-align:left;%1")); + path.text = path.text.arg(QString::fromLatin1("text-align:left;%1")); break; case 1: - path.text = path.text.arg(QString("text-align:center;%1")); + path.text = path.text.arg(QString::fromLatin1("text-align:center;%1")); break; case 2: - path.text = path.text.arg(QString("text-align:right;%1")); + path.text = path.text.arg(QString::fromLatin1("text-align:right;%1")); break; } switch(valignment) { case 0: - path.text = path.text.arg(QString("text-align:baseline;%1")); + path.text = path.text.arg(QString::fromLatin1("text-align:baseline;%1")); break; case 1: - path.text = path.text.arg(QString("text-align:bottom;%1")); + path.text = path.text.arg(QString::fromLatin1("text-align:bottom;%1")); break; case 2: - path.text = path.text.arg(QString("text-align:middle;%1")); + path.text = path.text.arg(QString::fromLatin1("text-align:middle;%1")); break; case 3: - path.text = path.text.arg(QString("text-align:top;%1")); + path.text = path.text.arg(QString::fromLatin1("text-align:top;%1")); } - path.text = path.text.arg(""); + path.text = path.text.arg(QString{}); //qDebug() << path.text; path.coords.append(co); p->append(path); diff --git a/src/dxfparser.h b/src/dxfparser.h index 1d0edb81f..9019cda60 100644 --- a/src/dxfparser.h +++ b/src/dxfparser.h @@ -127,7 +127,7 @@ DXFCoordinate::DXFCoordinate() inline DXFPath::DXFPath(type_e type) - : layer("1"), + : layer(QLatin1Char('1')), color(127,127,127), thickness(0), radius(0), diff --git a/src/file_format.cpp b/src/file_format.cpp index 3fcb5b08e..0cec7dd21 100644 --- a/src/file_format.cpp +++ b/src/file_format.cpp @@ -19,6 +19,8 @@ #include "file_format.h" +#include + // ### FileFormatException ### @@ -38,17 +40,17 @@ const char* FileFormatException::what() const noexcept // ### FileFormat ### -FileFormat::FileFormat(FileFormat::FileType file_type, const QString& id, const QString& description, const QString& file_extension, FileFormat::FormatFeatures features) +FileFormat::FileFormat(FileFormat::FileType file_type, const char* id, const QString& description, const QString& file_extension, FileFormat::FormatFeatures features) : file_type(file_type), format_id(id), format_description(description), format_features(features) { Q_ASSERT(file_type != 0); - Q_ASSERT(!id.isEmpty()); + Q_ASSERT(qstrlen(id) > 0); Q_ASSERT(!description.isEmpty()); - Q_ASSERT(!file_extension.isEmpty()); - addExtension(file_extension); + if (!file_extension.isEmpty()) + addExtension(file_extension); } FileFormat::~FileFormat() @@ -59,7 +61,7 @@ FileFormat::~FileFormat() void FileFormat::addExtension(const QString& file_extension) { file_extensions << file_extension; - format_filter = QString("%1 (*.%2)").arg(format_description).arg(file_extensions.join(" *.")); + format_filter = QString::fromLatin1("%1 (*.%2)").arg(format_description, file_extensions.join(QString::fromLatin1(" *."))); } bool FileFormat::understands(const unsigned char *buffer, size_t sz) const @@ -74,7 +76,7 @@ Importer *FileFormat::createImporter(QIODevice* stream, Map *map, MapView *view) Q_UNUSED(stream); Q_UNUSED(map); Q_UNUSED(view); - throw FileFormatException(QString("Format (%1) does not support import").arg(description())); + throw FileFormatException(QCoreApplication::translate("Importer", "Format (%1) does not support import").arg(description())); } Exporter *FileFormat::createExporter(QIODevice* stream, Map *map, MapView *view) const @@ -82,5 +84,5 @@ Exporter *FileFormat::createExporter(QIODevice* stream, Map *map, MapView *view) Q_UNUSED(stream); Q_UNUSED(map); Q_UNUSED(view); - throw FileFormatException(QString("Format (%1) does not support export").arg(description())); + throw FileFormatException(QCoreApplication::translate("Exporter", "Format (%1) does not support export").arg(description())); } diff --git a/src/file_format.h b/src/file_format.h index 4af29ec4a..4f25b2dd4 100644 --- a/src/file_format.h +++ b/src/file_format.h @@ -42,6 +42,11 @@ class FileFormatException : public std::exception */ FileFormatException(const QString& message = QString()); + /** Creates a new exception with the given message + * \param message a text describing the exceptional event that has occured. + */ + FileFormatException(const char* message); + /** Copy-constructor (C++ FAQ 17.17). */ FileFormatException(const FileFormatException& other) noexcept; @@ -100,8 +105,9 @@ class FileFormat enum FileType { MapFile = 0x01, + OgrFile = 0x02, ///< Geospatial vector data supported by OGR - AllFiles = MapFile, + AllFiles = MapFile, ///< All types which can be handled by an editor. EndOfFileTypes }; @@ -132,7 +138,7 @@ class FileFormat * Don't use a leading dot on the file extension. * */ - FileFormat(FileType file_type, const QString& id, const QString& description, const QString& file_extension, FormatFeatures features); + FileFormat(FileType file_type, const char* id, const QString& description, const QString& file_extension, FormatFeatures features); /** Destroys the file format information. */ virtual ~FileFormat(); @@ -148,7 +154,7 @@ class FileFormat /** Returns the internal ID of the file format. */ - const QString& id() const; + const char* id() const; /** Returns a short human-readable description of the file format. */ @@ -209,7 +215,7 @@ class FileFormat private: FileType file_type; - QString format_id; + const char* format_id; QString format_description; QStringList file_extensions; QString format_filter; @@ -227,6 +233,14 @@ FileFormatException::FileFormatException(const QString& message) // Nothing } +inline +FileFormatException::FileFormatException(const char* message) + : msg(QString::fromLatin1(message)) + , msg_c(message) +{ + // Nothing +} + inline FileFormatException::FileFormatException(const FileFormatException& other) noexcept : msg(other.msg) @@ -255,7 +269,7 @@ FileFormat::FileType FileFormat::fileType() const } inline -const QString& FileFormat::id() const +const char* FileFormat::id() const { return format_id; } diff --git a/src/file_format_native.cpp b/src/file_format_native.cpp index 2cc1c6bca..f73936c2b 100644 --- a/src/file_format_native.cpp +++ b/src/file_format_native.cpp @@ -89,7 +89,7 @@ const int NativeFileFormat::current_file_format_version = 30; const char NativeFileFormat::magic_bytes[4] = {0x4F, 0x4D, 0x41, 0x50}; // "OMAP" NativeFileFormat::NativeFileFormat() - : FileFormat(FileFormat::MapFile, "native (deprecated)", ImportExport::tr("OpenOrienteering Mapper").append(" pre-0.5"), "omap", + : FileFormat(FileFormat::MapFile, "native (deprecated)", ImportExport::tr("OpenOrienteering Mapper").append(QLatin1String(" pre-0.5")), QString::fromLatin1("omap"), FileFormat::ImportSupported) { // Nothing @@ -410,7 +410,7 @@ void NativeFileImport::import(bool load_symbols_only) for (int i = 0; i < num_parts; ++i) { - MapPart* part = new MapPart("", map); + MapPart* part = new MapPart({}, map); if (!part->load(stream, version, map)) { throw FileFormatException(Importer::tr("Error while loading map part %2.").arg(i+1)); diff --git a/src/file_format_ocad8.cpp b/src/file_format_ocad8.cpp index 9313e9efa..dcd725f77 100644 --- a/src/file_format_ocad8.cpp +++ b/src/file_format_ocad8.cpp @@ -1,6 +1,6 @@ /* * Copyright 2012, 2013 Pete Curtis - * Copyright 2013-2015 Kai Pastor + * Copyright 2013-2016 Kai Pastor * * This file is part of OpenOrienteering. * @@ -54,7 +54,7 @@ // ### OCAD8FileFormat ### OCAD8FileFormat::OCAD8FileFormat() - : FileFormat(MapFile, "OCAD78", ImportExport::tr("OCAD Versions 7, 8"), "ocd", + : FileFormat(MapFile, "OCAD78", ImportExport::tr("OCAD Versions 7, 8"), QString::fromLatin1("ocd"), ImportSupported | ExportSupported | ExportLossy) { // Nothing @@ -97,7 +97,7 @@ OCAD8FileImport::~OCAD8FileImport() bool OCAD8FileImport::isRasterImageFile(const QString &filename) { - int dot_pos = filename.lastIndexOf('.'); + int dot_pos = filename.lastIndexOf(QLatin1Char('.')); if (dot_pos < 0) return false; QString extension = filename.right(filename.length() - dot_pos - 1).toLower(); @@ -612,7 +612,7 @@ Symbol *OCAD8FileImport::importLineSymbol(const OCADLineSymbol *ocad_symbol) { symbol_line->setSuppressDashSymbolAtLineEnds(true); if (symbol_line->dash_symbol && symbol_line->number[0] != 799) - addWarning(tr("Line symbol %1: suppressing dash symbol at line ends.").arg(QString::number(0.1 * ocad_symbol->number) + " " + symbol_line->getName())); + addWarning(tr("Line symbol %1: suppressing dash symbol at line ends.").arg(QString::number(0.1 * ocad_symbol->number) + QLatin1Char(' ') + symbol_line->getName())); } // TODO: taper fields (tmode and tlast) @@ -828,7 +828,7 @@ OCAD8FileImport::RectangleInfo* OCAD8FileImport::importRectSymbol(const OCADRect rect.text = new TextSymbol(); fillCommonSymbolFields(rect.text, (OCADSymbol *)ocad_symbol); rect.text->setNumberComponent(2, 2); - rect.text->font_family = "Arial"; + rect.text->font_family = QString::fromLatin1("Arial"); rect.text->font_size = qRound(1000 * (15 / 72.0 * 25.4)); rect.text->color = rect.border_line->color; rect.text->bold = true; @@ -1180,9 +1180,9 @@ Template *OCAD8FileImport::importTemplate(OCADCString* ocad_str) Template* templ = NULL; QByteArray data(ocad_str->str); // copies the data. QString filename = encoding_1byte->toUnicode(data.left(data.indexOf('\t', 0))); - QString clean_path = QDir::cleanPath(QString(filename).replace('\\', '/')); + QString clean_path = QDir::cleanPath(QString(filename).replace(QLatin1Char('\\'), QLatin1Char('/'))); QString extension = QFileInfo(clean_path).suffix(); - if (extension.compare("ocd", Qt::CaseInsensitive) == 0) + if (extension.compare(QLatin1String("ocd"), Qt::CaseInsensitive) == 0) { templ = new TemplateMap(clean_path, map); } @@ -1283,7 +1283,7 @@ OCADBackground OCAD8FileImport::importBackground(const QByteArray& data) Template *OCAD8FileImport::importRasterTemplate(const OCADBackground &background) { QString filename(encoding_1byte->toUnicode(background.filename)); - filename = QDir::cleanPath(filename.replace('\\', '/')); + filename = QDir::cleanPath(filename.replace(QLatin1Char('\\'), QLatin1Char('/'))); if (isRasterImageFile(filename)) { TemplateImage* templ = new TemplateImage(filename, map); @@ -1598,7 +1598,7 @@ void OCAD8FileExport::doExport() ocad_color->magenta = qRound(1 / 0.005f * cmyk.m); ocad_color->yellow = qRound(1 / 0.005f * cmyk.y); ocad_color->black = qRound(1 / 0.005f * cmyk.k); - convertPascalString(QString("Registration black"), ocad_color->name, 32); // not translated + convertPascalString(QString::fromLatin1("Registration black"), ocad_color->name, 32); // not translated ++ocad_color_index; } @@ -1799,8 +1799,8 @@ void OCAD8FileExport::doExport() const Template* temp = map->getTemplate(i); QString template_path = temp->getTemplatePath(); - if ( temp->getTemplateType() == "TemplateImage" || - QFileInfo(template_path).suffix().compare("ocd", Qt::CaseInsensitive) == 0 ) + if (qstrcmp(temp->getTemplateType(), "TemplateImage") == 0 + || QFileInfo(template_path).suffix().compare(QLatin1String("ocd"), Qt::CaseInsensitive) == 0) { // FIXME: export template view parameters @@ -1816,7 +1816,7 @@ void OCAD8FileExport::doExport() double u = convertTemplateScale(temp->getTemplateScaleX()); double v = convertTemplateScale(temp->getTemplateScaleY()); - template_path.replace('/', '\\'); + template_path.replace(QLatin1Char('/'), QLatin1Char('\\')); QString string; string.sprintf("%s\ts%d\tx%d\ty%d\ta%f\tu%f\tv%f\td%d\tp%d\tt%d\to%d", @@ -2381,10 +2381,7 @@ u16 OCAD8FileExport::exportCoordinates(const MapCoordVector& coords, OCADPoint** for (size_t i = 0, end = coords.size(); i < end; ++i) { const MapCoord& point = coords[i]; - OCADPoint p; - p.x = (point.nativeX() / 10) << 8; - p.y = (point.nativeY() / -10) << 8; - + OCADPoint p = convertPoint(point); if (point.isDashPoint()) { if (symbol == NULL || symbol->getType() != Symbol::Line) @@ -2601,11 +2598,11 @@ int OCAD8FileExport::convertWideCString(const QString& text, unsigned char* buff // - if it starts with a newline, add another // - convert \n to \r\n QString exported_text; - if (text.startsWith('\n')) - exported_text = "\n" + text; + if (text.startsWith(QLatin1Char('\n'))) + exported_text = QLatin1Char('\n') + text; else exported_text = text; - exported_text.replace('\n', "\r\n"); + exported_text.replace(QLatin1Char('\n'), QLatin1String("\r\n")); if (2 * (exported_text.length() + 1) > buffer_size) addStringTruncationWarning(exported_text, buffer_size - 1); @@ -2627,13 +2624,20 @@ int OCAD8FileExport::convertRotation(float angle) return qRound(10 * (angle * 180 / M_PI)); } +namespace +{ + constexpr s32 convertPointMember(s32 value) + { + return (value < 0) ? (0x80000000 | ((0x7fffffu & ((value-5)/10)) << 8)) : ((0x7fffffu & ((value+5)/10)) << 8); + } + +} + OCADPoint OCAD8FileExport::convertPoint(qint32 x, qint32 y) { - OCADPoint result; - result.x = (s32)qRound(x / 10.0) << 8; - result.y = (s32)qRound(y / -10.0) << 8; - return result; + return { convertPointMember(x), convertPointMember(-y) }; } + OCADPoint OCAD8FileExport::convertPoint(const MapCoord& coord) { return convertPoint(coord.nativeX(), coord.nativeY()); @@ -2641,7 +2645,7 @@ OCADPoint OCAD8FileExport::convertPoint(const MapCoord& coord) s32 OCAD8FileExport::convertSize(qint32 size) { - return (s32)(size / 10); + return (s32)((size+5) / 10); } s16 OCAD8FileExport::convertColor(const MapColor* color) const @@ -2662,6 +2666,6 @@ double OCAD8FileExport::convertTemplateScale(double mapper_scale) void OCAD8FileExport::addStringTruncationWarning(const QString& text, int truncation_pos) { QString temp = text; - temp.insert(truncation_pos, "|||"); + temp.insert(truncation_pos, QLatin1String("|||")); addWarning(tr("String truncated (truncation marked with three '|'): %1").arg(temp)); } diff --git a/src/file_format_registry.cpp b/src/file_format_registry.cpp index 6c2036001..2ac7d145d 100644 --- a/src/file_format_registry.cpp +++ b/src/file_format_registry.cpp @@ -1,5 +1,6 @@ /* * Copyright 2012, 2013 Pete Curtis + * Copyright 2013, 2015, 2016 Kai Pastor * * This file is part of OpenOrienteering. * @@ -36,15 +37,27 @@ void FileFormatRegistry::registerFormat(FileFormat *format) { fmts.push_back(format); if (fmts.size() == 1) default_format_id = format->id(); - Q_ASSERT(findFormatForFilename("filename."+format->primaryExtension()) != NULL); // There may be more than one format! + Q_ASSERT(findFormatForFilename(QLatin1String("filename.") + format->primaryExtension()) != nullptr); // There may be more than one format! Q_ASSERT(findFormatByFilter(format->filter()) == format); // The filter shall be unique at least by description. } -const FileFormat *FileFormatRegistry::findFormat(const QString& id) const +std::unique_ptr FileFormatRegistry::unregisterFormat(const FileFormat* format) +{ + std::unique_ptr ret; + auto it = std::find(begin(fmts), end(fmts), format); + if (it != end(fmts)) + { + ret.reset(*it); + fmts.erase(it); + } + return ret; +} + +const FileFormat *FileFormatRegistry::findFormat(const char* id) const { for (auto format : fmts) { - if (format->id() == id) return format; + if (qstrcmp(format->id(), id) == 0) return format; } return NULL; } diff --git a/src/file_format_registry.h b/src/file_format_registry.h index 8dce9b2f2..a687d1832 100644 --- a/src/file_format_registry.h +++ b/src/file_format_registry.h @@ -1,5 +1,6 @@ /* * Copyright 2012, 2013 Pete Curtis + * Copyright 2013, 2016 Kai Pastor * * This file is part of OpenOrienteering. * @@ -20,6 +21,7 @@ #ifndef _OPENORIENTEERING_FILE_FORMAT_REGISTRY_H #define _OPENORIENTEERING_FILE_FORMAT_REGISTRY_H +#include #include #include @@ -54,7 +56,7 @@ class FileFormatRegistry /** Finds a file format with the given internal ID, or returns NULL if no format * is found. */ - const FileFormat *findFormat(const QString& id) const; + const FileFormat *findFormat(const char* id) const; /** Finds a file format which implements the given filter, or returns NULL if no * format is found. @@ -69,15 +71,22 @@ class FileFormatRegistry /** Returns the ID of default file format for this registry. This will automatically * be set to the first registered format. */ - const QString& defaultFormat() const { return default_format_id; } + const char* defaultFormat() const { return default_format_id; } /** Registers a new file format. The registry takes ownership of the provided Format. */ void registerFormat(FileFormat *format); + /** + * Unregisters a file format. + * + * Returns a non-const pointer to the file format and transfers ownership to the caller. + */ + std::unique_ptr unregisterFormat(const FileFormat *format); + private: std::vector fmts; - QString default_format_id; + const char* default_format_id; }; /** A FileFormatRegistry that is globally defined for convenience. Within the scope of a single diff --git a/src/file_format_xml.cpp b/src/file_format_xml.cpp index 4c000faa6..300b54ddd 100644 --- a/src/file_format_xml.cpp +++ b/src/file_format_xml.cpp @@ -25,7 +25,6 @@ #include #include #include -#include #include #include @@ -59,22 +58,22 @@ const int XMLFileFormat::current_version = 6; int XMLFileFormat::active_version = 5; // updated by XMLFileExporter::doExport() -const QString XMLFileFormat::magic_string = "= len && memcmp(buffer, magic_string.toUtf8().data(), len) == 0) - return true; - return false; + static const uint len = qstrlen(magic_string); + return (sz >= len && memcmp(buffer, magic_string, len) == 0); } Importer *XMLFileFormat::createImporter(QIODevice* stream, Map *map, MapView *view) const @@ -166,13 +165,13 @@ XMLFileExporter::XMLFileExporter(QIODevice* stream, Map *map, MapView *view) { // Determine auto-formatting default from filename, if possible. auto file = qobject_cast(stream); - bool auto_formatting = (file && file->fileName().contains(".xmap")); - setOption("autoFormatting", auto_formatting); + bool auto_formatting = (file && file->fileName().contains(QLatin1String(".xmap"))); + setOption(QString::fromLatin1("autoFormatting"), auto_formatting); } void XMLFileExporter::doExport() { - if (option("autoFormatting").toBool() == true) + if (option(QString::fromLatin1("autoFormatting")).toBool()) xml.setAutoFormatting(true); int current_version = XMLFileFormat::current_version; @@ -184,7 +183,7 @@ void XMLFileExporter::doExport() throw FileFormatException(tr("Older versions of Mapper do not support multiple map parts. To save the map in compatibility mode, you must first merge all map parts.")); } - xml.writeDefaultNamespace(XMLFileFormat::mapper_namespace); + xml.writeDefaultNamespace(mapper_namespace); xml.writeStartDocument(); { diff --git a/src/file_format_xml.h b/src/file_format_xml.h index 2200ffe4e..de10c054f 100644 --- a/src/file_format_xml.h +++ b/src/file_format_xml.h @@ -59,13 +59,6 @@ class XMLFileFormat : public FileFormat */ static int active_version; - /** @brief The characteristic magic string at the beginning of the file - */ - static const QString magic_string; - - /** @brief The XML namespace of the Mapper XML file format - */ - static const QString mapper_namespace; }; #endif // _OPENORIENTEERING_FILE_FORMAT_XML_H diff --git a/src/file_import_export.cpp b/src/file_import_export.cpp index 4625aa23f..3b0ed4002 100644 --- a/src/file_import_export.cpp +++ b/src/file_import_export.cpp @@ -90,7 +90,7 @@ void Importer::doImport(bool load_symbols_only, const QString& map_path) if (auto deleted = map->deleteIrregularObjects()) { - addWarning(tr("Dropped %n irregular object(s).", "", deleted)); + addWarning(tr("Dropped %n irregular object(s).", 0, deleted)); } // Symbol post processing @@ -108,18 +108,30 @@ void Importer::doImport(bool load_symbols_only, const QString& map_path) bool loaded_from_template_dir = false; temp->tryToFindAndReloadTemplateFile(map_path, &loaded_from_template_dir); + if (loaded_from_template_dir) + { addWarning(Importer::tr("Template \"%1\" has been loaded from the map's directory instead of the relative location to the map file where it was previously.").arg(temp->getTemplateFilename())); + } if (temp->getTemplateState() != Template::Loaded) + { have_lost_template = true; + addWarning(tr("Failed to load template '%1', reason: %2") + .arg(temp->getTemplateFilename(), temp->errorString())); + } + else if (!temp->errorString().isEmpty()) + { + addWarning(tr("Warnings when loading template '%1':\n%2") + .arg(temp->getTemplateFilename(), temp->errorString())); + } } if (have_lost_template) { #if defined(Q_OS_ANDROID) addWarning(tr("At least one template file could not be found.")); #else - addWarning(tr("At least one template file could not be found.") + " " + + addWarning(tr("At least one template file could not be found.") + QLatin1Char(' ') + tr("Click the red template name(s) in the Templates -> Template setup window to locate the template file name(s).")); #endif } diff --git a/src/fileformats/ocd_file_export.cpp b/src/fileformats/ocd_file_export.cpp new file mode 100644 index 000000000..6a67ed865 --- /dev/null +++ b/src/fileformats/ocd_file_export.cpp @@ -0,0 +1,47 @@ +/* + * Copyright 2016 Kai Pastor + * + * Some parts taken from file_format_oc*d8{.h,_p.h,cpp} which are + * Copyright 2012 Pete Curtis + * + * This file is part of OpenOrienteering. + * + * OpenOrienteering 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. + * + * OpenOrienteering 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 OpenOrienteering. If not, see . + */ + +#include "ocd_file_export.h" + +#include "../file_format_ocad8_p.h" + + +OcdFileExport::OcdFileExport(QIODevice* stream, Map* map, MapView* view) +: Exporter { stream, map, view } +{ + // nothing else +} + +OcdFileExport::~OcdFileExport() +{ + // nothing +} + +void OcdFileExport::doExport() +{ + OCAD8FileExport delegate { stream, map, view }; + delegate.doExport(); + for (auto&& w : delegate.warnings()) + { + addWarning(w); + } +} diff --git a/src/fileformats/ocd_file_export.h b/src/fileformats/ocd_file_export.h new file mode 100644 index 000000000..79a2188e0 --- /dev/null +++ b/src/fileformats/ocd_file_export.h @@ -0,0 +1,49 @@ +/* + * Copyright 2016 Kai Pastor + * + * Some parts taken from file_format_oc*d8{.h,_p.h,cpp} which are + * Copyright 2012 Pete Curtis + * + * This file is part of OpenOrienteering. + * + * OpenOrienteering 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. + * + * OpenOrienteering 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 OpenOrienteering. If not, see . + */ + +#ifndef OPENORIENTEERING_OCD_FILE_EXPORT_H +#define OPENORIENTEERING_OCD_FILE_EXPORT_H + +#include "../file_import_export.h" + + +/** + * An exporter for OCD files. + */ +class OcdFileExport : public Exporter +{ +Q_OBJECT +public: + OcdFileExport(QIODevice* stream, Map *map, MapView *view); + + ~OcdFileExport() override; + + /** + * Exports an OCD file. + * + * For now, this simply uses the OCAD8FileExport class. + */ + void doExport() override; + +}; + +#endif diff --git a/src/fileformats/ocd_file_format.cpp b/src/fileformats/ocd_file_format.cpp index eb2be10f8..05d108028 100644 --- a/src/fileformats/ocd_file_format.cpp +++ b/src/fileformats/ocd_file_format.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 Kai Pastor + * Copyright 2013-2016 Kai Pastor * * Some parts taken from file_format_oc*d8{.h,_p.h,cpp} which are * Copyright 2012 Pete Curtis @@ -21,42 +21,16 @@ */ #include "ocd_file_format.h" -#include "ocd_file_format_p.h" -#include -#include -#include -#include -#include - -#include "ocd_types_v8.h" -#include "ocd_types_v9.h" -#include "ocd_types_v10.h" -#include "ocd_types_v11.h" -#include "../core/map_color.h" -#include "../core/map_view.h" -#include "../core/georeferencing.h" -#include "../file_format_ocad8.h" -#include "../file_format_ocad8_p.h" -#include "../map.h" -#include "../object_text.h" -#include "../settings.h" -#include "../symbol_area.h" -#include "../symbol_combined.h" -#include "../symbol_line.h" -#include "../symbol_point.h" -#include "../symbol_text.h" -#include "../template.h" -#include "../template_image.h" -#include "../template_map.h" -#include "../util.h" +#include "ocd_file_export.h" +#include "ocd_file_import.h" // ### OcdFileFormat ### OcdFileFormat::OcdFileFormat() - : FileFormat(MapFile, "OCD", ImportExport::tr("OCAD"), "ocd", - ImportSupported | ExportSupported | ExportLossy) +: FileFormat { MapFile, "OCD", ImportExport::tr("OCAD"), QString::fromLatin1("ocd"), + ImportSupported | ExportSupported | ExportLossy } { // Nothing } @@ -76,1870 +50,6 @@ Importer* OcdFileFormat::createImporter(QIODevice* stream, Map *map, MapView *vi Exporter* OcdFileFormat::createExporter(QIODevice* stream, Map* map, MapView* view) const { - return new OCAD8FileExport(stream, map, view); -} - - -// ### OcdFileImport ### - -OcdFileImport::OcdFileImport(QIODevice* stream, Map* map, MapView* view) - : Importer(stream, map, view) - , delegate(nullptr) -{ - custom_8bit_encoding = QTextCodec::codecForName("Windows-1252"); -} - -OcdFileImport::~OcdFileImport() -{ - // nothing -} - -void OcdFileImport::setCustom8BitEncoding(const char* encoding) -{ - custom_8bit_encoding = QTextCodec::codecForName(encoding); -} - -void OcdFileImport::addSymbolWarning(LineSymbol* symbol, const QString& warning) -{ - addWarning( tr("In line symbol %1 '%2': %3"). - arg(symbol->getNumberAsString()). - arg(symbol->getName()). - arg(warning) ); -} - -void OcdFileImport::addSymbolWarning(TextSymbol* symbol, const QString& warning) -{ - addWarning( tr("In text symbol %1 '%2': %3"). - arg(symbol->getNumberAsString()). - arg(symbol->getName()). - arg(warning) ); -} - -#ifndef NDEBUG - -// Heuristic detection of implementation errors -template< > -inline -qint64 OcdFileImport::convertLength< quint8 >(quint8 ocd_length) const -{ - // OC*D uses hundredths of a millimeter. - // oo-mapper uses 1/1000 mm - if (ocd_length > 200) - qDebug() << "quint8 has value" << ocd_length << ", might be qint8" << (qint8)ocd_length; - return ((qint64)ocd_length) * 10; -} - -template< > -inline -qint64 OcdFileImport::convertLength< quint16 >(quint16 ocd_length) const -{ - // OC*D uses hundredths of a millimeter. - // oo-mapper uses 1/1000 mm - if (ocd_length > 50000) - qDebug() << "quint16 has value" << ocd_length << ", might be qint16" << (qint16)ocd_length; - return ((qint64)ocd_length) * 10; -} - -template< > -inline -qint64 OcdFileImport::convertLength< quint32 >(quint32 ocd_length) const -{ - // OC*D uses hundredths of a millimeter. - // oo-mapper uses 1/1000 mm - if (ocd_length > 3000000) - qDebug() << "quint32 has value" << ocd_length << ", might be qint32" << (qint32)ocd_length; - return ((qint64)ocd_length) * 10; -} -#endif // !NDEBUG - -template< > -void OcdFileImport::importImplementation< Ocd::FormatLegacyImporter >(bool load_symbols_only) -{ - QBuffer new_stream(&buffer); - new_stream.open(QIODevice::ReadOnly); - delegate.reset(new OCAD8FileImport(&new_stream, map, view)); - - delegate->import(load_symbols_only); - - for (auto&& w : delegate->warnings()) - { - addWarning(w); - } - - for (auto&& a : delegate->actions()) - { - addAction(a); - } -} - -template< class F > -void OcdFileImport::importImplementation(bool load_symbols_only) -{ - OcdFile< F > file(buffer); -#if 0 - for (auto&& string : file.strings()) - { - qDebug() << string.type << convertOcdString< typename F::Encoding >(file[string]); - } -#endif - - importGeoreferencing< F >(file); - importColors< F >(file); - importSymbols< F >(file); - if (!load_symbols_only) - { - importExtras< F >(file); - importObjects< F >(file); - importTemplates< F >(file); - if (view) - { - importView< F >(file); - } - } -} - -template< > -void OcdFileImport::importGeoreferencing< Ocd::FormatV8 >(const OcdFile< Ocd::FormatV8 >& file) -{ - const Ocd::FileHeaderV8* header = file.header(); - const Ocd::SetupV8* setup = reinterpret_cast< const Ocd::SetupV8* >(file.byteArray().data() + header->setup_pos); - - Georeferencing georef; - georef.setScaleDenominator(setup->map_scale); - georef.setProjectedRefPoint(QPointF(setup->real_offset_x, setup->real_offset_y)); - if (qAbs(setup->real_angle) >= 0.01) /* degrees */ - { - georef.setGrivation(setup->real_angle); - } - map->setGeoreferencing(georef); -} - -template< class F > -void OcdFileImport::importGeoreferencing(const OcdFile< F >& file) -{ - for (auto&& string : file.strings()) - { - if (string.type == 1039) - { - importScalesSettings(convertOcdString< typename F::Encoding >(file[string])); - break; - } - } -} - -void OcdFileImport::importScalesSettings(const QString& param_string) -{ - const QChar* unicode = param_string.unicode(); - - Georeferencing georef; - QPointF proj_ref_point; - bool x_ok = false, y_ok = false; - - int i = param_string.indexOf('\t', 0); - ; // skip first word for this entry type - while (i >= 0) - { - bool ok; - int next_i = param_string.indexOf('\t', i+1); - int len = (next_i > 0 ? next_i : param_string.length()) - i - 2; - const QString param_value = QString::fromRawData(unicode+i+2, len); // no copying! - switch (param_string[i+1].toLatin1()) - { - case '\t': - // empty item - break; - case 'm': - { - double scale = param_value.toDouble(&ok); - if (ok && scale >= 0) georef.setScaleDenominator(qRound(scale)); - break; - } - case 'a': - { - double angle = param_value.toDouble(&ok); - if (ok && qAbs(angle) >= 0.01) georef.setGrivation(angle); - break; - } - case 'x': - { - proj_ref_point.setX(param_value.toDouble(&x_ok)); - break; - } - case 'y': - { - proj_ref_point.setY(param_value.toDouble(&y_ok)); - break; - } - case 'd': - { - auto spacing = param_value.toDouble(&ok); - if (ok && spacing >= 0.001) - { - auto grid = map->getGrid(); - grid.setUnit(MapGrid::MetersInTerrain); - grid.setHorizontalSpacing(spacing); - grid.setVerticalSpacing(spacing); - map->setGrid(grid); - } - break; - } - default: - ; // nothing - } - i = next_i; - } - - if (x_ok && y_ok) - { - georef.setProjectedRefPoint(proj_ref_point); - } - - map->setGeoreferencing(georef); -} - -template< > -void OcdFileImport::importColors< struct Ocd::FormatV8 >(const OcdFile< Ocd::FormatV8 >& file) -{ - const Ocd::SymbolHeaderV8 & symbol_header = file.header()->symbol_header; - int num_colors = symbol_header.num_colors; - - for (int i = 0; i < num_colors && i < 256; i++) - { - const Ocd::ColorInfoV8& color_info = symbol_header.color_info[i]; - const QString name = convertOcdString(color_info.name); - int color_pos = map->getNumColors(); - MapColor* color = new MapColor(name, color_pos); - - // OC*D stores CMYK values as integers from 0-200. - MapColorCmyk cmyk; - cmyk.c = 0.005f * color_info.cmyk.cyan; - cmyk.m = 0.005f * color_info.cmyk.magenta; - cmyk.y = 0.005f * color_info.cmyk.yellow; - cmyk.k = 0.005f * color_info.cmyk.black; - color->setCmyk(cmyk); - color->setOpacity(1.0f); - - map->addColor(color, color_pos); - color_index[color_info.number] = color; - } - - addWarning(OcdFileImport::tr("Spot color information was ignored.")); -} - -template< class F > -void OcdFileImport::importColors(const OcdFile< F >& file) -{ - for (auto&& string : file.strings()) - { - if (string.type == 9) - { - importColor(convertOcdString< typename F::Encoding >(file[string])); - } - } - addWarning(tr("Spot color information was ignored.")); -} - -MapColor* OcdFileImport::importColor(const QString& param_string) -{ - const QChar* unicode = param_string.unicode(); - - int i = param_string.indexOf('\t', 0); - const QString name = param_string.left(qMax(-1, i)); // copied - - int number; - bool number_ok = false; - MapColorCmyk cmyk; - bool overprinting = false; - float opacity = 1.0f; - - while (i >= 0) - { - float f_value; - int i_value; - bool ok; - int next_i = param_string.indexOf('\t', i+1); - int len = (next_i > 0 ? next_i : param_string.length()) - i - 2; - const QString param_value = QString::fromRawData(unicode+i+2, len); // no copying! - switch (param_string[i+1].toLatin1()) - { - case '\t': - // empty item - break; - case 'n': - number = param_value.toInt(&number_ok); - break; - case 'c': - f_value = param_value.toFloat(&ok); - if (ok && f_value >= 0 && f_value <= 100) - cmyk.c = 0.01f * f_value; - break; - case 'm': - f_value = param_value.toFloat(&ok); - if (ok && f_value >= 0 && f_value <= 100) - cmyk.m = 0.01f * f_value; - break; - case 'y': - f_value = param_value.toFloat(&ok); - if (ok && f_value >= 0 && f_value <= 100) - cmyk.y = 0.01f * f_value; - break; - case 'k': - f_value = param_value.toFloat(&ok); - if (ok && f_value >= 0 && f_value <= 100) - cmyk.k = 0.01f * f_value; - break; - case 'o': - i_value = param_value.toInt(&ok); - if (ok) - overprinting = i_value; - break; - case 't': - f_value = param_value.toFloat(&ok); - if (ok && f_value >= 0.f && f_value <= 100.f) - opacity = 0.01f * f_value; - break; - default: - ; // nothing - } - i = next_i; - } - - if (!number_ok) - return nullptr; - - int color_pos = map->getNumColors(); - MapColor* color = new MapColor(name, color_pos); - color->setCmyk(cmyk); - color->setKnockout(!overprinting); - color->setOpacity(opacity); - map->addColor(color, color_pos); - color_index[number] = color; - - return color; -} - -template< class F > -void OcdFileImport::importSymbols(const OcdFile< F >& file) -{ - for (typename OcdFile< F >::SymbolIndex::iterator it = file.symbols().begin(); it != file.symbols().end(); ++it) - { - // When extra symbols are created, we want to insert the main symbol - // before them, i.e. at pos. - int pos = map->getNumSymbols(); - Symbol* symbol = nullptr; - - // Don't use switch, because F::SymbolType may have duplicate values. - if (it->type == F::TypePoint) - { - symbol = importPointSymbol((const typename F::PointSymbol&)*it); - } - else if (it->type == F::TypeLine) - { - symbol = importLineSymbol((const typename F::LineSymbol&)*it); - } - else if (it->type == F::TypeArea) - { - symbol = importAreaSymbol((const typename F::AreaSymbol&)*it, F::version()); - } - else if (it->type == F::TypeText) - { - symbol = importTextSymbol((const typename F::TextSymbol&)*it); - } - else if (it->type == F::TypeRectangle) - { - symbol = importRectangleSymbol((const typename F::RectangleSymbol&)*it); - } - else if (it->type == F::TypeLineText) - { - symbol = importLineTextSymbol((const typename F::LineTextSymbol&)*it); - } - else if (it->type) - { - addWarning(tr("Unable to import symbol %1.%2 \"%3\": %4") . - arg(it->number / F::BaseSymbol::symbol_number_factor) . - arg(it->number % F::BaseSymbol::symbol_number_factor) . - arg(convertOcdString(it->description)). - arg(tr("Unsupported type \"%1\".").arg(it->type)) ); - continue; - } - - map->addSymbol(symbol, pos); - symbol_index[it->number] = symbol; - } -} - -template< > -void OcdFileImport::importObjects< struct Ocd::FormatV8 >(const OcdFile< Ocd::FormatV8 >& file) -{ - MapPart* part = map->getCurrentPart(); - Q_ASSERT(part); - - for (auto&& object_entry : file.objects()) - { - if (object_entry.symbol) - { - auto object = importObject(file[object_entry], part); - if (object) - { - part->addObject(object, part->getNumObjects()); - } - } - } -} - -template< class F > -void OcdFileImport::importObjects(const OcdFile< F >& file) -{ - MapPart* part = map->getCurrentPart(); - Q_ASSERT(part); - - for (auto&& object_entry : file.objects()) - { - if ( object_entry.symbol - && object_entry.status != OcdFile< F >::ObjectIndex::EntryType::StatusDeleted - && object_entry.status != OcdFile< F >::ObjectIndex::EntryType::StatusDeletedForUndo ) - { - auto object = importObject(file[object_entry], part); - if (object) - { - part->addObject(object, part->getNumObjects()); - } - } - } -} - -template< class F > -void OcdFileImport::importTemplates(const OcdFile< F >& file) -{ - for (auto&& string : file.strings()) - { - if (string.type == 8) - { - importTemplate(convertOcdString< typename F::Encoding >(file[string]), F::version()); - } - } + return new OcdFileExport(stream, map, view); } -Template* OcdFileImport::importTemplate(const QString& param_string, const int ocd_version) -{ - const QChar* unicode = param_string.unicode(); - - int i = param_string.indexOf('\t', 0); - const QString filename = QString::fromRawData(unicode, qMax(-1, i)); - const QString clean_path = QDir::cleanPath(QString(filename).replace('\\', '/')); - const QString extension = QFileInfo(clean_path).suffix().toLower(); - - Template* templ = nullptr; - if (extension.compare("ocd") == 0) - { - templ = new TemplateMap(clean_path, map); - } - else if (QImageReader::supportedImageFormats().contains(extension.toLatin1())) - { - templ = new TemplateImage(clean_path, map); - } - else - { - addWarning(tr("Unable to import template: \"%1\" is not a supported template type.").arg(filename)); - return nullptr; - } - - // 8 or 9 or 10 ? Only tested with 8 and 11 - double scale_factor = (ocd_version <= 8) ? 0.01 : 1.0; - unsigned int num_rotation_params = 0; - double rotation = 0.0; - double scale_x = 1.0; - double scale_y = 1.0; - int dimming = 0; - bool visible = false; - - while (i >= 0) - { - double value; - bool ok; - int next_i = param_string.indexOf('\t', i+1); - int len = (next_i > 0 ? next_i : param_string.length()) - i - 2; - const QString param_value = QString::fromRawData(unicode+i+2, len); // no copying! - switch (param_string[i+1].toLatin1()) - { - case '\t': - // empty item - break; - case 'x': - value = param_value.toDouble(&ok); - if (ok) - templ->setTemplateX(qRound64(value*1000*scale_factor)); - break; - case 'y': - value = param_value.toDouble(&ok); - if (ok) - templ->setTemplateY(-qRound64(value*1000*scale_factor)); - break; - case 'a': - case 'b': - // TODO: use the distinct angles correctly, not just the average - rotation += param_value.toDouble(&ok); - if (ok) - ++num_rotation_params; - break; - case 'u': - value = param_value.toDouble(&ok); - if (ok && qAbs(value) >= 0.0000000001) - scale_x = value; - break; - case 'v': - value = param_value.toDouble(&ok); - if (ok && qAbs(value) >= 0.0000000001) - scale_y = value; - break; - case 'd': - dimming = param_value.toInt(); - break; - case 's': - visible = param_value.toInt(); - break; - default: - ; // nothing - } - i = next_i; - } - - if (num_rotation_params) - templ->setTemplateRotation(Georeferencing::degToRad(rotation / num_rotation_params)); - - templ->setTemplateScaleX(scale_x * scale_factor); - templ->setTemplateScaleY(scale_y * scale_factor); - - int template_pos = map->getFirstFrontTemplate(); - map->addTemplate(templ, 0, view); - map->setFirstFrontTemplate(template_pos+1); - - if (view) - { - TemplateVisibility* visibility = view->getTemplateVisibility(templ); - visibility->opacity = qMax(0.0, qMin(1.0, 0.01 * (100 - dimming))); - visibility->visible = visible; - } - - return templ; -} - -template< > -void OcdFileImport::importExtras< struct Ocd::FormatV8 >(const OcdFile< Ocd::FormatV8 >& file) -{ - const Ocd::FileHeaderV8* header = file.header(); - map->setMapNotes(convertOcdString< Ocd::FormatV8::Encoding >(file.byteArray().data() + header->info_pos, header->info_size)); -} - -template< class F > -void OcdFileImport::importExtras(const OcdFile< F >& file) -{ - QString notes; - - for (auto&& string : file.strings()) - { - switch (string.type) - { - case 11: - // OCD 9, 10 - notes.append(convertOcdString< typename F::Encoding >(file[string])); - notes.append("\n"); - break; - case 1061: - // OCD 11 - notes.append(convertOcdString< typename F::Encoding >(file[string])); - break; - default: - ; // nothing - } - } - - map->setMapNotes(notes); -} - -template< > -void OcdFileImport::importView< struct Ocd::FormatV8 >(const OcdFile< Ocd::FormatV8 >& file) -{ - if (view) - { - const Ocd::FileHeaderV8* header = file.header(); - const Ocd::SetupV8* setup = reinterpret_cast< const Ocd::SetupV8* >(file.byteArray().data() + header->setup_pos); - - if (setup->zoom >= MapView::zoom_out_limit && setup->zoom <= MapView::zoom_in_limit) - view->setZoom(setup->zoom); - - view->setCenter(convertOcdPoint(setup->center)); - } -} - -template< class F > -void OcdFileImport::importView(const OcdFile< F >& file) -{ - for (auto&& string : file.strings()) - { - if (string.type == 1030) - { - importView(convertOcdString< typename F::Encoding >(file[string])); - break; - } - } -} - -void OcdFileImport::importView(const QString& param_string) -{ - const QChar* unicode = param_string.unicode(); - - bool zoom_ok = false; - double zoom=1.0, offset_x=0.0, offset_y=0.0; - - int i = param_string.indexOf('\t', 0); - ; // skip first word for this entry type - while (i >= 0) - { - int next_i = param_string.indexOf('\t', i+1); - int len = (next_i > 0 ? next_i : param_string.length()) - i - 2; - const QString param_value = QString::fromRawData(unicode+i+2, len); // no copying! - switch (param_string[i+1].toLatin1()) - { - case '\t': - // empty item - break; - case 'x': - { - offset_x = param_value.toDouble(); - break; - } - case 'y': - { - offset_y = param_value.toDouble(); - break; - } - case 'z': - { - zoom = param_value.toDouble(&zoom_ok); - break; - } - default: - ; // nothing - } - i = next_i; - } - - if (view) - { - view->setCenter(MapCoord(offset_x, -offset_y)); - if (zoom_ok) - { - view->setZoom(zoom); - } - } -} - -template< class S > -void OcdFileImport::setupBaseSymbol(Symbol* symbol, const S& ocd_symbol) -{ - typedef typename S::BaseSymbol BaseSymbol; - const BaseSymbol& base_symbol = ocd_symbol.base; - // common fields are name, number, description, helper_symbol, hidden/protected status - symbol->setName(convertOcdString(base_symbol.description)); - symbol->setNumberComponent(0, base_symbol.number / BaseSymbol::symbol_number_factor); - symbol->setNumberComponent(1, base_symbol.number % BaseSymbol::symbol_number_factor); - symbol->setNumberComponent(2, -1); - symbol->setIsHelperSymbol(false); - if (base_symbol.status & BaseSymbol::StatusProtected) - symbol->setProtected(true); - if (base_symbol.status & BaseSymbol::StatusHidden) - symbol->setHidden(true); -} - -template< class S > -PointSymbol* OcdFileImport::importPointSymbol(const S& ocd_symbol) -{ - OcdImportedPointSymbol* symbol = new OcdImportedPointSymbol(); - setupBaseSymbol(symbol, ocd_symbol); - setupPointSymbolPattern(symbol, ocd_symbol.data_size, ocd_symbol.begin_of_elements); - symbol->setRotatable(ocd_symbol.base.flags & 1); - return symbol; -} - -template< class S > -Symbol* OcdFileImport::importLineSymbol(const S& ocd_symbol) -{ - OcdImportedLineSymbol* line_for_borders = nullptr; - - // Import a main line? - OcdImportedLineSymbol* main_line = nullptr; - if (ocd_symbol.double_mode == 0 || ocd_symbol.line_width > 0) - { - main_line = new OcdImportedLineSymbol(); - line_for_borders = main_line; - setupBaseSymbol(main_line, ocd_symbol); - - // Basic line options - main_line->line_width = convertLength(ocd_symbol.line_width); - main_line->color = convertColor(ocd_symbol.line_color); - - // Cap and join styles - switch (ocd_symbol.line_style) - { - case S::BevelJoin_FlatCap: - main_line->join_style = LineSymbol::BevelJoin; - main_line->cap_style = LineSymbol::FlatCap; - break; - case S::RoundJoin_RoundCap: - main_line->join_style = LineSymbol::RoundJoin; - main_line->cap_style = LineSymbol::RoundCap; - break; - case S::BevelJoin_PointedCap: - main_line->join_style = LineSymbol::BevelJoin; - main_line->cap_style = LineSymbol::PointedCap; - break; - case S::RoundJoin_PointedCap: - main_line->join_style = LineSymbol::RoundJoin; - main_line->cap_style = LineSymbol::PointedCap; - break; - case S::MiterJoin_FlatCap: - main_line->join_style = LineSymbol::MiterJoin; - main_line->cap_style = LineSymbol::FlatCap; - break; - case S::MiterJoin_PointedCap: - main_line->join_style = LineSymbol::MiterJoin; - main_line->cap_style = LineSymbol::PointedCap; - break; - default: - addSymbolWarning( main_line, - tr("Unsupported line style '%1'."). - arg(ocd_symbol.line_style) ); - } - - if (main_line->cap_style == LineSymbol::PointedCap) - { - int ocd_length = ocd_symbol.dist_from_start; - if (ocd_symbol.dist_from_start != ocd_symbol.dist_from_end) - { - // FIXME: Different lengths for start and end length of pointed line ends are not supported yet, so take the average - ocd_length = (ocd_symbol.dist_from_start + ocd_symbol.dist_from_end) / 2; - addSymbolWarning( main_line, - tr("Different lengths for pointed caps at begin (%1 mm) and end (%2 mm) are not supported. Using %3 mm."). - arg(locale.toString(0.001f * convertLength(ocd_symbol.dist_from_start))). - arg(locale.toString(0.001f * convertLength(ocd_symbol.dist_from_end))). - arg(locale.toString(0.001f * convertLength(ocd_length))) ); - } - main_line->pointed_cap_length = convertLength(ocd_length); - main_line->join_style = LineSymbol::RoundJoin; // NOTE: while the setting may be different (see what is set in the first place), OC*D always draws round joins if the line cap is pointed! - } - - // Handle the dash pattern - if (ocd_symbol.main_gap || ocd_symbol.sec_gap) - { - if (!ocd_symbol.main_length) - { - // Invalid dash pattern - addSymbolWarning( main_line, - tr("The dash pattern cannot be imported correctly.") ); - } - else if (ocd_symbol.sec_gap && !ocd_symbol.main_gap) - { - // Special case main_gap == 0 - main_line->dashed = true; - main_line->dash_length = convertLength(ocd_symbol.main_length - ocd_symbol.sec_gap); - main_line->break_length = convertLength(ocd_symbol.sec_gap); - - if (ocd_symbol.end_length) - { - if (qAbs((qint32)ocd_symbol.main_length - 2*ocd_symbol.end_length) > 1) - { - // End length not equal to 0.5 * main length - addSymbolWarning( main_line, - tr("The dash pattern's end length (%1 mm) cannot be imported correctly. Using %2 mm."). - arg(locale.toString(0.001f * convertLength(ocd_symbol.end_length))). - arg(locale.toString(0.001f * main_line->dash_length)) ); - } - if (ocd_symbol.end_gap) - { - addSymbolWarning( main_line, - tr("The dash pattern's end gap (%1 mm) cannot be imported correctly. Using %2 mm."). - arg(locale.toString(0.001f * convertLength(ocd_symbol.end_gap))). - arg(locale.toString(0.001f * main_line->break_length)) ); - } - } - } - else - { - // Standard case - main_line->dashed = true; - main_line->dash_length = convertLength(ocd_symbol.main_length); - main_line->break_length = convertLength(ocd_symbol.main_gap); - - if (ocd_symbol.end_length && ocd_symbol.end_length != ocd_symbol.main_length) - { - if (ocd_symbol.main_length && 0.75 >= ocd_symbol.end_length / ocd_symbol.main_length) - { - // End length max. 75 % of main length - main_line->half_outer_dashes = true; - } - - if (qAbs((qint32)ocd_symbol.main_length - 2*ocd_symbol.end_length) > 1) - { - // End length not equal to 0.5 * main length - addSymbolWarning( main_line, - tr("The dash pattern's end length (%1 mm) cannot be imported correctly. Using %2 mm."). - arg(locale.toString(0.001f * convertLength(ocd_symbol.end_length))). - arg(locale.toString(0.001f * (main_line->half_outer_dashes ? (main_line->dash_length/2) : main_line->dash_length))) ); - } - } - - if (ocd_symbol.sec_gap) - { - main_line->dashes_in_group = 2; - main_line->in_group_break_length = convertLength(ocd_symbol.sec_gap); - main_line->dash_length = (main_line->dash_length - main_line->in_group_break_length) / 2; - - if (ocd_symbol.end_length && ocd_symbol.end_gap != ocd_symbol.sec_gap) - { - addSymbolWarning( main_line, - tr("The dash pattern's end gap (%1 mm) cannot be imported correctly. Using %2 mm."). - arg(locale.toString(0.001f * convertLength(ocd_symbol.end_gap))). - arg(locale.toString(0.001f * main_line->in_group_break_length)) ); - } - } - } - } - else - { - main_line->segment_length = convertLength(ocd_symbol.main_length); - main_line->end_length = convertLength(ocd_symbol.end_length); - } - } - - // Import a 'framing' line? - OcdImportedLineSymbol* framing_line = nullptr; - if (ocd_symbol.framing_width > 0) - { - framing_line = new OcdImportedLineSymbol(); - if (!line_for_borders) - line_for_borders = framing_line; - setupBaseSymbol(framing_line, ocd_symbol); - - // Basic line options - framing_line->line_width = convertLength(ocd_symbol.framing_width); - framing_line->color = convertColor(ocd_symbol.framing_color); - - // Cap and join styles - switch (ocd_symbol.framing_style) - { - case S::BevelJoin_FlatCap: - framing_line->join_style = LineSymbol::BevelJoin; - framing_line->cap_style = LineSymbol::FlatCap; - break; - case S::RoundJoin_RoundCap: - framing_line->join_style = LineSymbol::RoundJoin; - framing_line->cap_style = LineSymbol::RoundCap; - break; - case S::MiterJoin_FlatCap: - framing_line->join_style = LineSymbol::MiterJoin; - framing_line->cap_style = LineSymbol::FlatCap; - break; - default: - addSymbolWarning( main_line, - tr("Unsupported framing line style '%1'."). - arg(ocd_symbol.line_style) ); - } - } - - // Import a 'double' line? - bool has_border_line = - (ocd_symbol.double_mode != 0) && - (ocd_symbol.double_left_width > 0 || ocd_symbol.double_right_width > 0); - OcdImportedLineSymbol *double_line = nullptr; - if ( has_border_line && - (ocd_symbol.double_flags & S::DoubleFillColorOn || (has_border_line && !line_for_borders))) - { - double_line = new OcdImportedLineSymbol(); - line_for_borders = double_line; - setupBaseSymbol(double_line, ocd_symbol); - - double_line->line_width = convertLength(ocd_symbol.double_width); - if (ocd_symbol.double_flags & S::DoubleFillColorOn) - double_line->color = convertColor(ocd_symbol.double_color); - else - double_line->color = nullptr; - - double_line->cap_style = LineSymbol::FlatCap; - double_line->join_style = LineSymbol::MiterJoin; - - double_line->segment_length = convertLength(ocd_symbol.main_length); - double_line->end_length = convertLength(ocd_symbol.end_length); - } - - // Border lines - if (has_border_line) - { - Q_ASSERT(line_for_borders); - line_for_borders->have_border_lines = true; - LineSymbolBorder& border = line_for_borders->getBorder(); - LineSymbolBorder& right_border = line_for_borders->getRightBorder(); - - // Border color and width - border.color = convertColor(ocd_symbol.double_left_color); - border.width = convertLength(ocd_symbol.double_left_width); - border.shift = convertLength(ocd_symbol.double_left_width) / 2 + (convertLength(ocd_symbol.double_width) - line_for_borders->line_width) / 2; - - right_border.color = convertColor(ocd_symbol.double_right_color); - right_border.width = convertLength(ocd_symbol.double_right_width); - right_border.shift = convertLength(ocd_symbol.double_right_width) / 2 + (convertLength(ocd_symbol.double_width) - line_for_borders->line_width) / 2; - - // The borders may be dashed - if (ocd_symbol.double_gap > 0 && ocd_symbol.double_mode > 1) - { - border.dashed = true; - border.dash_length = convertLength(ocd_symbol.double_length); - border.break_length = convertLength(ocd_symbol.double_gap); - - // If ocd_symbol->dmode == 2, only the left border should be dashed - if (ocd_symbol.double_mode > 2) - { - right_border.dashed = border.dashed; - right_border.dash_length = border.dash_length; - right_border.break_length = border.break_length; - } - } - } - - // Create point symbols along line; middle ("normal") dash, corners, start, and end. - OcdImportedLineSymbol* symbol_line = main_line ? main_line : double_line; // Find the line to attach the symbols to - if (symbol_line == nullptr) - { - main_line = new OcdImportedLineSymbol(); - symbol_line = main_line; - setupBaseSymbol(main_line, ocd_symbol); - - main_line->segment_length = convertLength(ocd_symbol.main_length); - main_line->end_length = convertLength(ocd_symbol.end_length); - } - - const Ocd::OcdPoint32* coords = reinterpret_cast(ocd_symbol.begin_of_elements); - - symbol_line->mid_symbol = new OcdImportedPointSymbol(); - setupPointSymbolPattern(symbol_line->mid_symbol, ocd_symbol.primary_data_size, ocd_symbol.begin_of_elements); - symbol_line->mid_symbols_per_spot = ocd_symbol.num_prim_sym; - symbol_line->mid_symbol_distance = convertLength(ocd_symbol.prim_sym_dist); - coords += ocd_symbol.primary_data_size; - - if (ocd_symbol.secondary_data_size > 0) - { - //symbol_line->dash_symbol = importPattern( ocd_symbol->ssnpts, symbolptr); - coords += ocd_symbol.secondary_data_size; - addSymbolWarning(symbol_line, tr("Skipped secondary point symbol.")); - } - if (ocd_symbol.corner_data_size > 0) - { - symbol_line->dash_symbol = new OcdImportedPointSymbol(); - setupPointSymbolPattern(symbol_line->dash_symbol, ocd_symbol.corner_data_size, reinterpret_cast(coords)); - symbol_line->dash_symbol->setName(LineSymbolSettings::tr("Dash symbol")); - coords += ocd_symbol.corner_data_size; - } - if (ocd_symbol.start_data_size > 0) - { - symbol_line->start_symbol = new OcdImportedPointSymbol(); - setupPointSymbolPattern(symbol_line->start_symbol, ocd_symbol.start_data_size, reinterpret_cast(coords)); - symbol_line->start_symbol->setName(LineSymbolSettings::tr("Start symbol")); - coords += ocd_symbol.start_data_size; - } - if (ocd_symbol.end_data_size > 0) - { - symbol_line->end_symbol = new OcdImportedPointSymbol(); - setupPointSymbolPattern(symbol_line->end_symbol, ocd_symbol.end_data_size, reinterpret_cast(coords)); - symbol_line->end_symbol->setName(LineSymbolSettings::tr("End symbol")); - } - // FIXME: not really sure how this translates... need test cases - symbol_line->minimum_mid_symbol_count = 0; //1 + ocd_symbol->smin; - symbol_line->minimum_mid_symbol_count_when_closed = 0; //1 + ocd_symbol->smin; - symbol_line->show_at_least_one_symbol = false; // NOTE: this works in a different way than OC*D's 'at least X symbols' setting (per-segment instead of per-object) - - // Suppress dash symbol at line ends if both start symbol and end symbol exist, - // but don't create a warning unless a dash symbol is actually defined - // and the line symbol is not Mapper's 799 Simple orienteering course. - if (symbol_line->start_symbol != nullptr && symbol_line->end_symbol != nullptr) - { - symbol_line->setSuppressDashSymbolAtLineEnds(true); - if (symbol_line->dash_symbol && symbol_line->number[0] != 799) - { - addSymbolWarning(symbol_line, tr("Suppressing dash symbol at line ends.")); - } - } - - // TODO: taper fields (tmode and tlast) - - if (main_line == nullptr && framing_line == nullptr) - return double_line; - else if (double_line == nullptr && framing_line == nullptr) - return main_line; - else if (main_line == nullptr && double_line == nullptr) - return framing_line; - else - { - CombinedSymbol* full_line = new CombinedSymbol(); - setupBaseSymbol(full_line, ocd_symbol); - full_line->setNumParts(3); - int part = 0; - if (main_line) - { - full_line->setPart(part++, main_line, true); - main_line->setHidden(false); - main_line->setProtected(false); - } - if (double_line) - { - full_line->setPart(part++, double_line, true); - double_line->setHidden(false); - double_line->setProtected(false); - } - if (framing_line) - { - full_line->setPart(part++, framing_line, true); - framing_line->setHidden(false); - framing_line->setProtected(false); - } - full_line->setNumParts(part); - addSymbolWarning(symbol_line, tr("This symbol cannot be saved as a proper OCD symbol again.")); - return full_line; - } -} - -template< class S > -AreaSymbol* OcdFileImport::importAreaSymbol(const S& ocd_symbol, int ocd_version) -{ - OcdImportedAreaSymbol* symbol = new OcdImportedAreaSymbol(); - setupBaseSymbol(symbol, ocd_symbol); - - // Basic area symbol fields: minimum_area, color - symbol->minimum_area = 0; - symbol->color = ocd_symbol.fill_on ? convertColor(ocd_symbol.fill_color) : nullptr; - - symbol->patterns.clear(); - symbol->patterns.reserve(4); - - // Hatching - if (ocd_symbol.hatch_mode != S::HatchNone) - { - AreaSymbol::FillPattern pattern; - pattern.type = AreaSymbol::FillPattern::LinePattern; - pattern.angle = convertAngle(ocd_symbol.hatch_angle_1); - pattern.rotatable = true; - pattern.line_spacing = convertLength(ocd_symbol.hatch_dist); - pattern.line_offset = 0; - pattern.line_color = convertColor(ocd_symbol.hatch_color); - pattern.line_width = convertLength(ocd_symbol.hatch_line_width); - if (ocd_version <= 8) - { - pattern.line_spacing += pattern.line_width; - } - symbol->patterns.push_back(pattern); - - if (ocd_symbol.hatch_mode == S::HatchCross) - { - // Second hatch, same as the first, just a different angle - pattern.angle = convertAngle(ocd_symbol.hatch_angle_2); - symbol->patterns.push_back(pattern); - } - } - - if (ocd_symbol.structure_mode != S::StructureNone) - { - AreaSymbol::FillPattern pattern; - pattern.type = AreaSymbol::FillPattern::PointPattern; - pattern.angle = convertAngle(ocd_symbol.structure_angle); - pattern.rotatable = true; - pattern.point_distance = convertLength(ocd_symbol.structure_width); - pattern.line_spacing = convertLength(ocd_symbol.structure_height); - pattern.line_offset = 0; - pattern.offset_along_line = 0; - // FIXME: somebody needs to own this symbol and be responsible for deleting it - // Right now it looks like a potential memory leak - pattern.point = new OcdImportedPointSymbol(); - setupPointSymbolPattern(pattern.point, ocd_symbol.data_size, ocd_symbol.begin_of_elements); - - // OC*D 8 has a "staggered" pattern mode, where successive rows are shifted width/2 relative - // to each other. We need to simulate this in Mapper with two overlapping patterns, each with - // twice the height. The second is then offset by width/2, height/2. - if (ocd_symbol.structure_mode == S::StructureShiftedRows) - { - pattern.line_spacing *= 2; - symbol->patterns.push_back(pattern); - - pattern.line_offset = pattern.line_spacing / 2; - pattern.offset_along_line = pattern.point_distance / 2; - pattern.point = pattern.point->duplicate()->asPoint(); - } - symbol->patterns.push_back(pattern); - } - - return symbol; -} - -template< class S > -TextSymbol* OcdFileImport::importTextSymbol(const S& ocd_symbol) -{ - OcdImportedTextSymbol* symbol = new OcdImportedTextSymbol(); - setupBaseSymbol(symbol, ocd_symbol); - - symbol->font_family = convertOcdString(ocd_symbol.font_name); // FIXME: font mapping? - symbol->color = convertColor(ocd_symbol.font_color); - double d_font_size = (0.1 * ocd_symbol.font_size) / 72.0 * 25.4; - symbol->font_size = qRound(1000 * d_font_size); - symbol->bold = (ocd_symbol.font_weight>= 550) ? true : false; - symbol->italic = (ocd_symbol.font_italic) ? true : false; - symbol->underline = false; - symbol->paragraph_spacing = convertLength(ocd_symbol.para_spacing); - symbol->character_spacing = ocd_symbol.char_spacing / 100.0; - symbol->kerning = false; - symbol->line_below = ocd_symbol.line_below_on; - symbol->line_below_color = convertColor(ocd_symbol.line_below_color); - symbol->line_below_width = convertLength(ocd_symbol.line_below_width); - symbol->line_below_distance = convertLength(ocd_symbol.line_below_offset); - symbol->custom_tabs.resize(ocd_symbol.num_tabs); - for (int i = 0; i < ocd_symbol.num_tabs; ++i) - symbol->custom_tabs[i] = convertLength(ocd_symbol.tab_pos[i]); - - TextObject::HorizontalAlignment halign = TextObject::AlignHCenter; - int ocd_halign = ocd_symbol.alignment & 3; - if (ocd_halign == 0) // TODO: Named identifiers, all values - halign = TextObject::AlignLeft; - else if (ocd_halign == 1) - halign = TextObject::AlignHCenter; - else if (ocd_halign == 2) - halign = TextObject::AlignRight; - else if (ocd_halign == 3) - addSymbolWarning(symbol, tr("Justified alignment is not supported.")); // TODO - - text_halign_map[symbol] = halign; - - TextObject::VerticalAlignment valign = TextObject::AlignBaseline; - int ocd_valign = ocd_symbol.alignment & 12; - if (ocd_valign == 4) // TODO: Named identifiers, all values - valign = TextObject::AlignVCenter; - else if (ocd_valign == 8) - valign = TextObject::AlignTop; - else if (ocd_valign == 12) - addSymbolWarning(symbol, tr("Vertical alignment '%1' is not supported.").arg(ocd_symbol.alignment)); // TODO - - text_valign_map[symbol] = valign; - - if (ocd_symbol.font_weight != 400 && ocd_symbol.font_weight != 700) - { - addSymbolWarning(symbol, tr("Ignoring custom weight (%1).").arg(ocd_symbol.font_weight)); - } - if (ocd_symbol.char_spacing != 0) - { - addSymbolWarning(symbol, tr("Custom character spacing may be incorrect.")); - } - if (ocd_symbol.word_spacing != 100) - { - addSymbolWarning(symbol, tr("Ignoring custom word spacing (%1 %).").arg(ocd_symbol.word_spacing)); - } - if (ocd_symbol.indent_first_line != 0 || ocd_symbol.indent_other_lines != 0) - { - addSymbolWarning(symbol, tr("Ignoring custom indents (%1/%2).").arg(ocd_symbol.indent_first_line).arg(ocd_symbol.indent_other_lines)); - } - - if (ocd_symbol.framing_mode > 0) // TODO: Identifiers - { - symbol->framing = true; - symbol->framing_color = convertColor(ocd_symbol.framing_color); - if (ocd_symbol.framing_mode == 1) - { - symbol->framing_mode = TextSymbol::ShadowFraming; - symbol->framing_shadow_x_offset = convertLength(ocd_symbol.framing_offset_x); - symbol->framing_shadow_y_offset = -1 * convertLength(ocd_symbol.framing_offset_y); - } - else if (ocd_symbol.framing_mode == 2) - { - symbol->framing_mode = TextSymbol::LineFraming; - symbol->framing_line_half_width = convertLength(ocd_symbol.framing_line_width); - } - else - { - addSymbolWarning(symbol, tr("Ignoring text framing (mode %1).").arg(ocd_symbol.framing_mode)); - } - } - - symbol->updateQFont(); - - // Convert line spacing - double absolute_line_spacing = d_font_size * 0.01 * ocd_symbol.line_spacing; - symbol->line_spacing = absolute_line_spacing / (symbol->getFontMetrics().lineSpacing() / symbol->calculateInternalScaling()); - - return symbol; -} - -template< class S > -TextSymbol* OcdFileImport::importLineTextSymbol(const S& ocd_symbol) -{ - OcdImportedTextSymbol* symbol = new OcdImportedTextSymbol(); - setupBaseSymbol(symbol, ocd_symbol); - - symbol->font_family = convertOcdString(ocd_symbol.font_name); // FIXME: font mapping? - symbol->color = convertColor(ocd_symbol.font_color); - double d_font_size = (0.1 * ocd_symbol.font_size) / 72.0 * 25.4; - symbol->font_size = qRound(1000 * d_font_size); - symbol->bold = (ocd_symbol.font_weight>= 550) ? true : false; - symbol->italic = (ocd_symbol.font_italic) ? true : false; - symbol->underline = false; - symbol->character_spacing = ocd_symbol.char_spacing / 100.0; - symbol->kerning = false; - symbol->line_below = false; - symbol->custom_tabs.resize(0); - - TextObject::HorizontalAlignment halign = TextObject::AlignHCenter; - int ocd_halign = ocd_symbol.alignment & 3; - if (ocd_halign == 0) // TODO: Named identifiers, all values - halign = TextObject::AlignLeft; - else if (ocd_halign == 1) - halign = TextObject::AlignHCenter; - else if (ocd_halign == 2) - halign = TextObject::AlignRight; - else if (ocd_halign == 3) - addSymbolWarning(symbol, tr("Justified alignment is not supported.")); // TODO - - text_halign_map[symbol] = halign; - - TextObject::VerticalAlignment valign = TextObject::AlignBaseline; - int ocd_valign = ocd_symbol.alignment & 12; - if (ocd_valign == 4) // TODO: Named identifiers, all values - valign = TextObject::AlignVCenter; - else if (ocd_valign == 8) - valign = TextObject::AlignTop; - else if (ocd_valign == 12) - addSymbolWarning(symbol, tr("Vertical alignment '%1' is not supported.").arg(ocd_symbol.alignment)); // TODO - - text_valign_map[symbol] = valign; - - if (ocd_symbol.font_weight != 400 && ocd_symbol.font_weight != 700) - { - addSymbolWarning(symbol, tr("Ignoring custom weight (%1).").arg(ocd_symbol.font_weight)); - } - if (ocd_symbol.char_spacing != 0) - { - addSymbolWarning(symbol, tr("Custom character spacing may be incorrect.")); - } - if (ocd_symbol.word_spacing != 100) - { - addSymbolWarning(symbol, tr("Ignoring custom word spacing (%1 %).").arg(ocd_symbol.word_spacing)); - } - - if (ocd_symbol.framing_mode > 0) // TODO: Identifiers - { - symbol->framing = true; - symbol->framing_color = convertColor(ocd_symbol.framing_color); - if (ocd_symbol.framing_mode == 1) - { - symbol->framing_mode = TextSymbol::ShadowFraming; - symbol->framing_shadow_x_offset = convertLength(ocd_symbol.framing_offset_x); - symbol->framing_shadow_y_offset = -1 * convertLength(ocd_symbol.framing_offset_y); - } - else if (ocd_symbol.framing_mode == 2) - { - symbol->framing_mode = TextSymbol::LineFraming; - symbol->framing_line_half_width = convertLength(ocd_symbol.framing_line_width); - } - else - { - addSymbolWarning(symbol, tr("Ignoring text framing (mode %1).").arg(ocd_symbol.framing_mode)); - } - } - - symbol->updateQFont(); - - addSymbolWarning(symbol, tr("Line text symbols are not yet supported. Marking the symbol as hidden.")); - symbol->setHidden(true); - - return symbol; -} - -template< class S > -LineSymbol* OcdFileImport::importRectangleSymbol(const S& ocd_symbol) -{ - OcdImportedLineSymbol* symbol = new OcdImportedLineSymbol(); - setupBaseSymbol(symbol, ocd_symbol); - - symbol->line_width = convertLength(ocd_symbol.line_width); - symbol->color = convertColor(ocd_symbol.line_color); - symbol->cap_style = LineSymbol::FlatCap; - symbol->join_style = LineSymbol::RoundJoin; - - RectangleInfo rect; - rect.border_line = symbol; - rect.corner_radius = 0.001 * convertLength(ocd_symbol.corner_radius); - rect.has_grid = ocd_symbol.grid_flags & 1; - - if (rect.has_grid) - { - OcdImportedLineSymbol* inner_line = new OcdImportedLineSymbol(); - setupBaseSymbol(inner_line, ocd_symbol); - inner_line->setNumberComponent(2, 1); // TODO: Dynamic - inner_line->line_width = qRound(1000 * 0.15); - inner_line->color = symbol->color; - map->addSymbol(inner_line, map->getNumSymbols()); - - OcdImportedTextSymbol* text = new OcdImportedTextSymbol(); - setupBaseSymbol(text, ocd_symbol); - text->setNumberComponent(2, 2); // TODO: Dynamic - text->font_family = "Arial"; - text->font_size = qRound(1000 * (15 / 72.0 * 25.4)); - text->color = symbol->color; - text->bold = true; - text->updateQFont(); - map->addSymbol(text, map->getNumSymbols()); - - rect.inner_line = inner_line; - rect.text = text; - rect.number_from_bottom = ocd_symbol.grid_flags & 2; - rect.cell_width = 0.001 * convertLength(ocd_symbol.cell_width); - rect.cell_height = 0.001 * convertLength(ocd_symbol.cell_height); - rect.unnumbered_cells = ocd_symbol.unnumbered_cells; - rect.unnumbered_text = convertOcdString(ocd_symbol.unnumbered_text); - } - rectangle_info.insert(ocd_symbol.base.number, rect); - - return symbol; -} - -template< > // OCD::FormatV8 -int OcdFileImport::circleRadius(const Ocd::PointSymbolElementV8* element) const -{ - return element->diameter / 2 - element->line_width; -} - -template< class E > -int OcdFileImport::circleRadius(const E* element) const -{ - return (element->diameter - element->line_width) / 2; -} - -template< class E > -void OcdFileImport::setupPointSymbolPattern(PointSymbol* symbol, std::size_t data_size, const E* elements) -{ - Q_ASSERT(symbol != nullptr); - - symbol->setRotatable(true); - bool base_symbol_used = false; - - for (std::size_t i = 0; i < data_size; i += 2) - { - const E* element = reinterpret_cast(&reinterpret_cast(elements)[i]); - const Ocd::OcdPoint32* const coords = reinterpret_cast(elements) + i + 2; - switch (element->type) - { - case E::TypeDot: - if (element->diameter > 0) - { - bool can_use_base_symbol = (!base_symbol_used && (!element->num_coords || (!coords[0].x && !coords[0].y))); - PointSymbol* working_symbol = can_use_base_symbol ? symbol : new PointSymbol(); - working_symbol->setInnerColor(convertColor(element->color)); - working_symbol->setInnerRadius(convertLength(element->diameter) / 2); - working_symbol->setOuterColor(nullptr); - working_symbol->setOuterWidth(0); - if (can_use_base_symbol) - { - base_symbol_used = true; - } - else - { - working_symbol->setRotatable(false); - PointObject* element_object = new PointObject(working_symbol); - if (element->num_coords) - { - const MapCoord coord = convertOcdPoint(coords[0]); - element_object->setPosition(coord.nativeX(), coord.nativeY()); - } - symbol->addElement(symbol->getNumElements(), element_object, working_symbol); - } - } - break; - case E::TypeCircle: - { - int element_radius = circleRadius(element); - if (element_radius > 0) - { - bool can_use_base_symbol = (!base_symbol_used && (!element->num_coords || (!coords[0].x && !coords[0].y))); - PointSymbol* working_symbol = can_use_base_symbol ? symbol : new PointSymbol(); - working_symbol->setInnerColor(nullptr); - working_symbol->setInnerRadius(convertLength(element_radius)); - working_symbol->setOuterColor(convertColor(element->color)); - working_symbol->setOuterWidth(convertLength(element->line_width)); - if (can_use_base_symbol) - { - base_symbol_used = true; - } - else - { - working_symbol->setRotatable(false); - PointObject* element_object = new PointObject(working_symbol); - if (element->num_coords) - { - const MapCoord coord = convertOcdPoint(coords[0]); - element_object->setPosition(coord.nativeX(), coord.nativeY()); - } - symbol->addElement(symbol->getNumElements(), element_object, working_symbol); - } - } - break; - } - case E::TypeLine: - { - OcdImportedLineSymbol* element_symbol = new OcdImportedLineSymbol(); - element_symbol->line_width = convertLength(element->line_width); - element_symbol->color = convertColor(element->color); - OcdImportedPathObject* element_object = new OcdImportedPathObject(element_symbol); - fillPathCoords(element_object, false, element->num_coords, coords); - element_object->recalculateParts(); - symbol->addElement(symbol->getNumElements(), element_object, element_symbol); - } - break; - case E::TypeArea: - { - OcdImportedAreaSymbol* element_symbol = new OcdImportedAreaSymbol(); - element_symbol->color = convertColor(element->color); - OcdImportedPathObject* element_object = new OcdImportedPathObject(element_symbol); - fillPathCoords(element_object, true, element->num_coords, coords); - element_object->recalculateParts(); - symbol->addElement(symbol->getNumElements(), element_object, element_symbol); - } - break; - default: - ; // TODO: not-supported warning - } - i += element->num_coords; - } -} - -template< class O > -Object* OcdFileImport::importObject(const O& ocd_object, MapPart* part) -{ - Symbol* symbol = nullptr; - if (ocd_object.symbol >= 0) - { - symbol = symbol_index[ocd_object.symbol]; - } - - if (!symbol) - { - switch (ocd_object.type) - { - case 1: - symbol = map->getUndefinedPoint(); - break; - case 2: - case 3: - symbol = map->getUndefinedLine(); - break; - case 4: - case 5: - symbol = map->getUndefinedText(); - break; - default: - addWarning(tr("Unable to load object")); - qDebug() << "Undefined object type" << ocd_object.type << " for object of symbol" << ocd_object.symbol; - return nullptr; - } - } - - if (symbol->getType() == Symbol::Line && rectangle_info.contains(ocd_object.symbol)) - { - Object* object = importRectangleObject(ocd_object, part, rectangle_info[ocd_object.symbol]); - if (!object) - addWarning(tr("Unable to import rectangle object")); - return object; - } - - if (symbol->getType() == Symbol::Point) - { - PointObject* p = new PointObject(); - p->setSymbol(symbol, true); - - // extra properties: rotation - PointSymbol* point_symbol = reinterpret_cast(symbol); - if (point_symbol->isRotatable()) - { - p->setRotation(convertAngle(ocd_object.angle)); - } - else if (ocd_object.angle != 0) - { - if (!point_symbol->isSymmetrical()) - { - point_symbol->setRotatable(true); - p->setRotation(convertAngle(ocd_object.angle)); - } - } - - const MapCoord pos = convertOcdPoint(ocd_object.coords[0]); - p->setPosition(pos.nativeX(), pos.nativeY()); - - p->setMap(map); - return p; - } - else if (symbol->getType() == Symbol::Text) - { - TextObject *t = new TextObject(symbol); - t->setText(getObjectText(ocd_object)); - t->setRotation(convertAngle(ocd_object.angle)); - t->setHorizontalAlignment(text_halign_map.value(symbol)); - // Vertical alignment is set in fillTextPathCoords(). - - // Text objects need special path translation - if (!fillTextPathCoords(t, reinterpret_cast(symbol), ocd_object.num_items, (Ocd::OcdPoint32 *)ocd_object.coords)) - { - addWarning(tr("Not importing text symbol, couldn't figure out path' (npts=%1): %2") - .arg(ocd_object.num_items).arg(t->getText())); - delete t; - return nullptr; - } - t->setMap(map); - return t; - } - else if (symbol->getType() == Symbol::Line || symbol->getType() == Symbol::Area || symbol->getType() == Symbol::Combined) - { - OcdImportedPathObject *p = new OcdImportedPathObject(symbol); - p->setPatternRotation(convertAngle(ocd_object.angle)); - - // Normal path - fillPathCoords(p, symbol->getType() == Symbol::Area, ocd_object.num_items, (Ocd::OcdPoint32*)ocd_object.coords); - p->recalculateParts(); - p->setMap(map); - return p; - } - - return nullptr; -} - -template< > -inline -QString OcdFileImport::getObjectText< struct Ocd::ObjectV8 >(const Ocd::ObjectV8& ocd_object) const -{ - QString object_text; - if (ocd_object.unicode) - { - object_text = convertOcdString((const QChar*)(ocd_object.coords + ocd_object.num_items)); - } - else - { - const size_t len = sizeof(Ocd::OcdPoint32) * ocd_object.num_text; - object_text = convertOcdString((const char*)(ocd_object.coords + ocd_object.num_items), len); - } - - // Remove leading "\r\n" - if (object_text.startsWith("\r\n")) - { - object_text.remove(0, 2); - } - - return object_text; -} - -template< class O > -inline -QString OcdFileImport::getObjectText(const O& ocd_object) const -{ - return QString((const QChar *)(ocd_object.coords + ocd_object.num_items)); -} - -template< class O > -Object* OcdFileImport::importRectangleObject(const O& ocd_object, MapPart* part, const OcdFileImport::RectangleInfo& rect) -{ - if (ocd_object.num_items != 4) - { - qDebug() << "importRectangleObject called with num_items =" << ocd_object.num_items << "for object of symbol" << ocd_object.symbol; - if (ocd_object.num_items != 5) // 5 coords are handled like 4 coords now - return nullptr; - } - - // Convert corner points - MapCoord bottom_left = convertOcdPoint(ocd_object.coords[0]); - MapCoord bottom_right = convertOcdPoint(ocd_object.coords[1]); - MapCoord top_right = convertOcdPoint(ocd_object.coords[2]); - MapCoord top_left = convertOcdPoint(ocd_object.coords[3]); - - MapCoordF top_left_f = MapCoordF(top_left); - MapCoordF top_right_f = MapCoordF(top_right); - MapCoordF bottom_left_f = MapCoordF(bottom_left); - MapCoordF bottom_right_f = MapCoordF(bottom_right); - MapCoordF right = MapCoordF(top_right.x() - top_left.x(), top_right.y() - top_left.y()); - double angle = right.angle(); - MapCoordF down = MapCoordF(bottom_left.x() - top_left.x(), bottom_left.y() - top_left.y()); - right.normalize(); - down.normalize(); - - // Create border line - MapCoordVector coords; - if (rect.corner_radius == 0) - { - coords.emplace_back(top_left); - coords.emplace_back(top_right); - coords.emplace_back(bottom_right); - coords.emplace_back(bottom_left); - } - else - { - double handle_radius = (1 - BEZIER_KAPPA) * rect.corner_radius; - coords.emplace_back(top_right_f - right * rect.corner_radius, MapCoord::CurveStart); - coords.emplace_back(top_right_f - right * handle_radius); - coords.emplace_back(top_right_f + down * handle_radius); - coords.emplace_back(top_right_f + down * rect.corner_radius); - coords.emplace_back(bottom_right_f - down * rect.corner_radius, MapCoord::CurveStart); - coords.emplace_back(bottom_right_f - down * handle_radius); - coords.emplace_back(bottom_right_f - right * handle_radius); - coords.emplace_back(bottom_right_f - right * rect.corner_radius); - coords.emplace_back(bottom_left_f + right * rect.corner_radius, MapCoord::CurveStart); - coords.emplace_back(bottom_left_f + right * handle_radius); - coords.emplace_back(bottom_left_f - down * handle_radius); - coords.emplace_back(bottom_left_f - down * rect.corner_radius); - coords.emplace_back(top_left_f + down * rect.corner_radius, MapCoord::CurveStart); - coords.emplace_back(top_left_f + down * handle_radius); - coords.emplace_back(top_left_f + right * handle_radius); - coords.emplace_back(top_left_f + right * rect.corner_radius); - } - PathObject *border_path = new PathObject(rect.border_line, coords, map); - border_path->parts().front().setClosed(true, false); - - if (rect.has_grid && rect.cell_width > 0 && rect.cell_height > 0) - { - // Calculate grid sizes - double width = top_left.distanceTo(top_right); - double height = top_left.distanceTo(bottom_left); - int num_cells_x = qMax(1, qRound(width / rect.cell_width)); - int num_cells_y = qMax(1, qRound(height / rect.cell_height)); - - float cell_width = width / num_cells_x; - float cell_height = height / num_cells_y; - - // Create grid lines - coords.resize(2); - for (int x = 1; x < num_cells_x; ++x) - { - coords[0] = MapCoord(top_left_f + x * cell_width * right); - coords[1] = MapCoord(bottom_left_f + x * cell_width * right); - - PathObject *path = new PathObject(rect.inner_line, coords, map); - part->addObject(path, part->getNumObjects()); - } - for (int y = 1; y < num_cells_y; ++y) - { - coords[0] = MapCoord(top_left_f + y * cell_height * down); - coords[1] = MapCoord(top_right_f + y * cell_height * down); - - PathObject *path = new PathObject(rect.inner_line, coords, map); - part->addObject(path, part->getNumObjects()); - } - - // Create grid text - if (height >= rect.cell_height / 2) - { - for (int y = 0; y < num_cells_y; ++y) - { - for (int x = 0; x < num_cells_x; ++x) - { - int cell_num; - QString cell_text; - - if (rect.number_from_bottom) - cell_num = y * num_cells_x + x + 1; - else - cell_num = (num_cells_y - 1 - y) * num_cells_x + x + 1; - - if (cell_num > num_cells_x * num_cells_y - rect.unnumbered_cells) - cell_text = rect.unnumbered_text; - else - cell_text = QString::number(cell_num); - - TextObject* object = new TextObject(rect.text); - object->setMap(map); - object->setText(cell_text); - object->setRotation(-angle); - object->setHorizontalAlignment(TextObject::AlignLeft); - object->setVerticalAlignment(TextObject::AlignTop); - double position_x = (x + 0.07f) * cell_width; - double position_y = (y + 0.04f) * cell_height + rect.text->getFontMetrics().ascent() / rect.text->calculateInternalScaling() - rect.text->getFontSize(); - object->setAnchorPosition(top_left_f + position_x * right + position_y * down); - part->addObject(object, part->getNumObjects()); - - //pts[0].Y -= rectinfo.gridText.FontAscent - rectinfo.gridText.FontEmHeight; - } - } - } - } - - return border_path; -} - -void OcdFileImport::setPathHolePoint(OcdImportedPathObject *object, int pos) -{ - // Look for curve start points before the current point and apply hole point only if no such point is there. - // This prevents hole points in the middle of a curve caused by incorrect map objects. - if (pos >= 1 && object->coords[pos].isCurveStart()) - ; //object->coords[i-1].setHolePoint(true); - else if (pos >= 2 && object->coords[pos-1].isCurveStart()) - ; //object->coords[i-2].setHolePoint(true); - else if (pos >= 3 && object->coords[pos-2].isCurveStart()) - ; //object->coords[i-3].setHolePoint(true); - else if (pos > 0) // Don't start with hole point. - object->coords[pos].setHolePoint(true); -} - -void OcdFileImport::setPointFlags(OcdImportedPathObject* object, quint16 pos, bool is_area, const Ocd::OcdPoint32& ocd_point) -{ - // We can support CurveStart, HolePoint, DashPoint. - // CurveStart needs to be applied to the main point though, not the control point, and - // hole points need to bet set as the last point of a part of an area object instead of the first point of the next part - if (ocd_point.x & Ocd::OcdPoint32::FlagCtl1 && pos > 0) - object->coords[pos-1].setCurveStart(true); - if ((ocd_point.y & Ocd::OcdPoint32::FlagDash) || (ocd_point.y & Ocd::OcdPoint32::FlagCorner)) - object->coords[pos].setDashPoint(true); - if (ocd_point.y & Ocd::OcdPoint32::FlagHole) - setPathHolePoint(object, is_area ? (pos - 1) : pos); -} - -/** Translates the OC*D path given in the last two arguments into an Object. - */ -void OcdFileImport::fillPathCoords(OcdImportedPathObject *object, bool is_area, quint16 num_points, const Ocd::OcdPoint32* ocd_points) -{ - object->coords.resize(num_points); - for (int i = 0; i < num_points; i++) - { - object->coords[i] = convertOcdPoint(ocd_points[i]); - setPointFlags(object, i, is_area, ocd_points[i]); - } - - // For path objects, create closed parts where the position of the last point is equal to that of the first point - if (object->getType() == Object::Path) - { - int start = 0; - for (int i = 0; i < (int)object->coords.size(); ++i) - { - if (!object->coords[i].isHolePoint() && i < (int)object->coords.size() - 1) - continue; - - if (object->coords[i].isPositionEqualTo(object->coords[start])) - { - MapCoord coord = object->coords[start]; - coord.setCurveStart(false); - coord.setHolePoint(true); - coord.setClosePoint(true); - object->coords[i] = coord; - } - - start = i + 1; - } - } -} - -/** Translates an OCAD text object path into a Mapper text object specifier, if possible. - * If successful, sets either 1 or 2 coordinates in the text object and returns true. - * If the OCAD path was not importable, leaves the TextObject alone and returns false. - */ -bool OcdFileImport::fillTextPathCoords(TextObject *object, TextSymbol *symbol, quint16 npts, const Ocd::OcdPoint32 *ocd_points) -{ - // text objects either have 1 point (free anchor) or 2 (midpoint/size) - // OCAD appears to always have 5 or 4 points (possible single anchor, then 4 corner coordinates going clockwise from anchor). - if (npts == 0) return false; - - if (npts == 4) - { - // Box text - MapCoord bottom_left = convertOcdPoint(ocd_points[0]); - MapCoord top_right = convertOcdPoint(ocd_points[2]); - MapCoord top_left = convertOcdPoint(ocd_points[3]); - - // According to Purple Pen source code: OC*D adds an extra internal leading (incorrectly). - QFontMetricsF metrics = symbol->getFontMetrics(); - double top_adjust = -symbol->getFontSize() + (metrics.ascent() + metrics.descent() + 0.5) / symbol->calculateInternalScaling(); - - MapCoordF adjust_vector = MapCoordF(top_adjust * sin(object->getRotation()), top_adjust * cos(object->getRotation())); - top_left = MapCoord(top_left.x() + adjust_vector.x(), top_left.y() + adjust_vector.y()); - top_right = MapCoord(top_right.x() + adjust_vector.x(), top_right.y() + adjust_vector.y()); - - object->setBox((bottom_left.nativeX() + top_right.nativeX()) / 2, (bottom_left.nativeY() + top_right.nativeY()) / 2, - top_left.distanceTo(top_right), top_left.distanceTo(bottom_left)); - object->setVerticalAlignment(TextObject::AlignTop); - } - else - { - // Single anchor text - if (npts != 5) - addWarning(tr("Trying to import a text object with unknown coordinate format")); - - // anchor point - MapCoord coord = convertOcdPoint(ocd_points[0]); - object->setAnchorPosition(coord.nativeX(), coord.nativeY()); - object->setVerticalAlignment(text_valign_map.value(symbol)); - } - - return true; -} - -void OcdFileImport::import(bool load_symbols_only) -{ - Q_ASSERT(buffer.isEmpty()); - - buffer.clear(); - buffer.append(stream->readAll()); - if (buffer.isEmpty()) - throw FileFormatException(Importer::tr("Could not read file: %1").arg(stream->errorString())); - - if (buffer.size() < (int)sizeof(Ocd::FormatGeneric::FileHeader)) - throw FileFormatException(Importer::tr("Could not read file: %1").arg(tr("Invalid data."))); - - OcdFile< Ocd::FormatGeneric > generic_file(buffer); - if (generic_file.header()->vendor_mark != 0x0cad) // This also tests correct endianess... - throw FileFormatException(Importer::tr("Could not read file: %1").arg(tr("Invalid data."))); - - int version = generic_file.header()->version; - switch (version) - { - case 6: - case 7: - // We keep the following existing translation just in case - // we add support for version 6/7 to the new importer. - /* addWarning( */ - (void)tr("Untested file importer for format: OCD %1").arg(version) - /* ) */; - importImplementation< Ocd::FormatLegacyImporter >(load_symbols_only); - break; - case 8: - if (Settings::getInstance().getSetting(Settings::General_NewOcd8Implementation).toBool()) - importImplementation< Ocd::FormatV8 >(load_symbols_only); - else - importImplementation< Ocd::FormatLegacyImporter >(load_symbols_only); - break; - case 9: - importImplementation< Ocd::FormatV9 >(load_symbols_only); - break; - case 10: - importImplementation< Ocd::FormatV10 >(load_symbols_only); - break; - case 11: - importImplementation< Ocd::FormatV11 >(load_symbols_only); - break; - default: - throw FileFormatException( - Importer::tr("Could not read file: %1"). - arg(tr("OCD files of version %1 are not supported!").arg(version)) - ); - } -} - -void OcdFileImport::finishImport() -{ - if (delegate) - { - // The current warnings and actions are already propagated. - std::size_t warnings_size = delegate->warnings().size(); - std::size_t actions_size = delegate->actions().size(); - - delegate->finishImport(); - - // Propagate new warnings and actions from the delegate to this importer. - std::for_each(begin(delegate->warnings()) + warnings_size, end(delegate->warnings()), [this](const QString& w) { addWarning(w); }); - std::for_each(begin(delegate->actions()) + actions_size, end(delegate->actions()), [this](const ImportAction& a) { addAction(a); }); - } -} diff --git a/src/fileformats/ocd_file_format.h b/src/fileformats/ocd_file_format.h index 3403110ce..793d3b5e2 100644 --- a/src/fileformats/ocd_file_format.h +++ b/src/fileformats/ocd_file_format.h @@ -1,5 +1,5 @@ /* - * Copyright 2013 Kai Pastor + * Copyright 2013, 2016 Kai Pastor * * This file is part of OpenOrienteering. * @@ -17,8 +17,8 @@ * along with OpenOrienteering. If not, see . */ -#ifndef _OPENORIENTEERING_OCD_FILE_FORMAT_ -#define _OPENORIENTEERING_OCD_FILE_FORMAT_ +#ifndef OPENORIENTEERING_OCD_FILE_FORMAT +#define OPENORIENTEERING_OCD_FILE_FORMAT #include "../file_format.h" @@ -35,21 +35,17 @@ class OcdFileFormat : public FileFormat /** * Detects whether the buffer may be the start of a valid OCD file. + * * At the moment, it requires at least two bytes of data. * It will return false if compiled for a big endian system. */ - bool understands(const unsigned char *buffer, size_t sz) const; + bool understands(const unsigned char *buffer, size_t sz) const override; - /** - * Creates an importer object and configures for the given input stream - * and output map and view. - */ - virtual Importer* createImporter(QIODevice* stream, Map *map, MapView *view) const; + /// \copydoc FileFormat::createImporter() + virtual Importer* createImporter(QIODevice* stream, Map *map, MapView *view) const override; - /** - * Creates an OCAD8FileFormat exporter. - */ - virtual Exporter* createExporter(QIODevice* stream, Map* map, MapView* view) const; + /// \copydoc FileFormat::createExporter() + virtual Exporter* createExporter(QIODevice* stream, Map* map, MapView* view) const override; }; -#endif // _OPENORIENTEERING_OCD_FILE_FORMAT_ +#endif // OPENORIENTEERING_OCD_FILE_FORMAT diff --git a/src/fileformats/ocd_file_import.cpp b/src/fileformats/ocd_file_import.cpp new file mode 100644 index 000000000..a154cfe7a --- /dev/null +++ b/src/fileformats/ocd_file_import.cpp @@ -0,0 +1,2020 @@ +/* + * Copyright 2013-2016 Kai Pastor + * + * Some parts taken from file_format_oc*d8{.h,_p.h,cpp} which are + * Copyright 2012 Pete Curtis + * + * This file is part of OpenOrienteering. + * + * OpenOrienteering 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. + * + * OpenOrienteering 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 OpenOrienteering. If not, see . + */ + +#include "ocd_file_import.h" + +#include +#include +#include +#include +#include + +#include "ocd_types_v9.h" +#include "ocd_types_v10.h" +#include "ocd_types_v11.h" +#include "ocd_types_v12.h" +#include "../core/crs_template.h" +#include "../core/map_color.h" +#include "../core/map_view.h" +#include "../core/georeferencing.h" +#include "../file_format_ocad8.h" +#include "../file_format_ocad8_p.h" +#include "../map.h" +#include "../object_text.h" +#include "../settings.h" +#include "../symbol_area.h" +#include "../symbol_combined.h" +#include "../symbol_line.h" +#include "../symbol_point.h" +#include "../symbol_text.h" +#include "../template.h" +#include "../template_image.h" +#include "../template_map.h" +#include "../util.h" + + +OcdFileImport::OcdFileImport(QIODevice* stream, Map* map, MapView* view) + : Importer { stream, map, view } + , delegate { nullptr } + , custom_8bit_encoding { QTextCodec::codecForName("Windows-1252") } +{ + // nothing else +} + +OcdFileImport::~OcdFileImport() +{ + // nothing +} + + +void OcdFileImport::setCustom8BitEncoding(const char* encoding) +{ + custom_8bit_encoding = QTextCodec::codecForName(encoding); +} + + +void OcdFileImport::addSymbolWarning(const LineSymbol* symbol, const QString& warning) +{ + addWarning( tr("In line symbol %1 '%2': %3"). + arg(symbol->getNumberAsString(), symbol->getName(), warning) ); +} + +void OcdFileImport::addSymbolWarning(const TextSymbol* symbol, const QString& warning) +{ + addWarning( tr("In text symbol %1 '%2': %3"). + arg(symbol->getNumberAsString(), symbol->getName(), warning) ); +} + + +#ifndef NDEBUG + +// Heuristic detection of implementation errors +template< > +inline +qint64 OcdFileImport::convertLength< quint8 >(quint8 ocd_length) const +{ + // OC*D uses hundredths of a millimeter. + // oo-mapper uses 1/1000 mm + if (ocd_length > 200) + qDebug() << "quint8 has value" << ocd_length << ", might be qint8" << (qint8)ocd_length; + return ((qint64)ocd_length) * 10; +} + +template< > +inline +qint64 OcdFileImport::convertLength< quint16 >(quint16 ocd_length) const +{ + // OC*D uses hundredths of a millimeter. + // oo-mapper uses 1/1000 mm + if (ocd_length > 50000) + qDebug() << "quint16 has value" << ocd_length << ", might be qint16" << (qint16)ocd_length; + return ((qint64)ocd_length) * 10; +} + +template< > +inline +qint64 OcdFileImport::convertLength< quint32 >(quint32 ocd_length) const +{ + // OC*D uses hundredths of a millimeter. + // oo-mapper uses 1/1000 mm + if (ocd_length > 3000000) + qDebug() << "quint32 has value" << ocd_length << ", might be qint32" << (qint32)ocd_length; + return ((qint64)ocd_length) * 10; +} + +#endif // !NDEBUG + + +void OcdFileImport::importImplementationLegacy(bool load_symbols_only) +{ + QBuffer new_stream(&buffer); + new_stream.open(QIODevice::ReadOnly); + delegate.reset(new OCAD8FileImport(&new_stream, map, view)); + + delegate->import(load_symbols_only); + + for (auto&& w : delegate->warnings()) + { + addWarning(w); + } + + for (auto&& a : delegate->actions()) + { + addAction(a); + } +} + +template< class F > +void OcdFileImport::importImplementation(bool load_symbols_only) +{ + OcdFile< F > file(buffer); +#ifdef MAPPER_DEVELOPMENT_BUILD + if (!qApp->applicationName().endsWith(QLatin1String("Test"))) + { + qDebug("*** OcdFileImport: Importing a version %d.%d file", file.header()->version, file.header()->subversion); + for (const auto& string : file.strings()) + { + qDebug(" %d \t%s", string.type, qPrintable(convertOcdString< typename F::Encoding >(file[string]))); + } + } +#endif + + importGeoreferencing(file); + importColors(file); + importSymbols(file); + if (!load_symbols_only) + { + importExtras(file); + importObjects(file); + importTemplates(file); + if (view) + { + importView(file); + } + } +} + + +void OcdFileImport::importGeoreferencing(const OcdFile& file) +{ + const Ocd::FileHeaderV8* header = file.header(); + const Ocd::SetupV8* setup = reinterpret_cast< const Ocd::SetupV8* >(file.byteArray().data() + header->setup_pos); + + Georeferencing georef; + georef.setScaleDenominator(setup->map_scale); + georef.setProjectedRefPoint(QPointF(setup->real_offset_x, setup->real_offset_y)); + if (qAbs(setup->real_angle) >= 0.01) /* degrees */ + { + georef.setGrivation(setup->real_angle); + } + map->setGeoreferencing(georef); +} + +template< class F > +void OcdFileImport::importGeoreferencing(const OcdFile< F >& file) +{ + for (auto&& string : file.strings()) + { + if (string.type == 1039) + { + importGeoreferencing(convertOcdString< typename F::Encoding >(file[string])); + break; + } + } +} + +void OcdFileImport::importGeoreferencing(const QString& param_string) +{ + const QChar* unicode = param_string.unicode(); + + Georeferencing georef; + QString combined_grid_zone; + QPointF proj_ref_point; + bool x_ok = false, y_ok = false; + + int i = param_string.indexOf(QLatin1Char('\t'), 0); + ; // skip first word for this entry type + while (i >= 0) + { + bool ok; + int next_i = param_string.indexOf(QLatin1Char('\t'), i+1); + int len = (next_i > 0 ? next_i : param_string.length()) - i - 2; + const QString param_value = QString::fromRawData(unicode+i+2, len); // no copying! + switch (param_string[i+1].toLatin1()) + { + case 'm': + { + double scale = param_value.toDouble(&ok); + if (ok && scale >= 0) + georef.setScaleDenominator(qRound(scale)); + } + break; + case 'a': + { + double angle = param_value.toDouble(&ok); + if (ok && qAbs(angle) >= 0.01) + georef.setGrivation(angle); + } + break; + case 'x': + proj_ref_point.setX(param_value.toDouble(&x_ok)); + break; + case 'y': + proj_ref_point.setY(param_value.toDouble(&y_ok)); + break; + case 'd': + { + auto spacing = param_value.toDouble(&ok); + if (ok && spacing >= 0.001) + { + auto grid = map->getGrid(); + grid.setUnit(MapGrid::MetersInTerrain); + grid.setHorizontalSpacing(spacing); + grid.setVerticalSpacing(spacing); + map->setGrid(grid); + } + } + break; + case 'i': + combined_grid_zone = param_value; + break; + case '\t': + // empty item, fall through + default: + ; // nothing + } + i = next_i; + } + + if (!combined_grid_zone.isEmpty()) + { + applyGridAndZone(georef, combined_grid_zone); + } + + if (x_ok && y_ok) + { + georef.setProjectedRefPoint(proj_ref_point); + } + + map->setGeoreferencing(georef); +} + +void OcdFileImport::applyGridAndZone(Georeferencing& georef, const QString& combined_grid_zone) +{ + bool zone_ok = false; + const CRSTemplate* crs_template = nullptr; + QString id; + QString spec; + std::vector values; + + if (combined_grid_zone.startsWith(QLatin1String("20"))) + { + auto zone = combined_grid_zone.midRef(2).toUInt(&zone_ok); + zone_ok &= (zone >= 1 && zone <= 60); + if (zone_ok) + { + id = QLatin1String{"UTM"}; + crs_template = CRSTemplateRegistry().find(id); + values.reserve(1); + values.push_back(QString::number(zone)); + } + } + else if (combined_grid_zone.startsWith(QLatin1String("80"))) + { + auto zone = combined_grid_zone.midRef(2).toUInt(&zone_ok); + if (zone_ok) + { + id = QLatin1String{"Gauss-Krueger, datum: Potsdam"}; + crs_template = CRSTemplateRegistry().find(id); + values.reserve(1); + values.push_back(QString::number(zone)); + } + } + else if (combined_grid_zone == QLatin1String("14000")) + { + id = QLatin1String{"EPSG"}; + crs_template = CRSTemplateRegistry().find(id); + values.reserve(1); + values.push_back(QLatin1String{"21781"}); + } + else if (combined_grid_zone == QLatin1String("1000")) + { + return; + } + + if (crs_template) + { + spec = crs_template->specificationTemplate(); + auto param = crs_template->parameters().begin(); + for (const auto& value : values) + { + for (const auto& spec_value : (*param)->specValues(value)) + { + spec = spec.arg(spec_value); + } + ++param; + } + } + + if (spec.isEmpty()) + { + addWarning(tr("Could not load the coordinate reference system '%1'.").arg(combined_grid_zone)); + } + else + { + georef.setProjectedCRS(id, spec, std::move(values)); + } +} + + +void OcdFileImport::importColors(const OcdFile& file) +{ + const Ocd::SymbolHeaderV8 & symbol_header = file.header()->symbol_header; + int num_colors = symbol_header.num_colors; + + for (int i = 0; i < num_colors && i < 256; i++) + { + const Ocd::ColorInfoV8& color_info = symbol_header.color_info[i]; + const QString name = convertOcdString(color_info.name); + int color_pos = map->getNumColors(); + MapColor* color = new MapColor(name, color_pos); + + // OC*D stores CMYK values as integers from 0-200. + MapColorCmyk cmyk; + cmyk.c = 0.005f * color_info.cmyk.cyan; + cmyk.m = 0.005f * color_info.cmyk.magenta; + cmyk.y = 0.005f * color_info.cmyk.yellow; + cmyk.k = 0.005f * color_info.cmyk.black; + color->setCmyk(cmyk); + color->setOpacity(1.0f); + + map->addColor(color, color_pos); + color_index[color_info.number] = color; + } + + addWarning(OcdFileImport::tr("Spot color information was ignored.")); +} + +template< class F > +void OcdFileImport::importColors(const OcdFile< F >& file) +{ + for (auto&& string : file.strings()) + { + if (string.type == 9) + { + importColor(convertOcdString< typename F::Encoding >(file[string])); + } + } + addWarning(tr("Spot color information was ignored.")); +} + +MapColor* OcdFileImport::importColor(const QString& param_string) +{ + const QChar* unicode = param_string.unicode(); + + int i = param_string.indexOf(QLatin1Char('\t'), 0); + const QString name = param_string.left(qMax(-1, i)); // copied + + int number; + bool number_ok = false; + MapColorCmyk cmyk { 0.0, 0.0, 0.0, 0.0 }; + bool overprinting = false; + float opacity = 1.0f; + + while (i >= 0) + { + float f_value; + int i_value; + bool ok; + int next_i = param_string.indexOf(QLatin1Char('\t'), i+1); + int len = (next_i > 0 ? next_i : param_string.length()) - i - 2; + const QString param_value = QString::fromRawData(unicode+i+2, len); // no copying! + switch (param_string[i+1].toLatin1()) + { + case '\t': + // empty item + break; + case 'n': + number = param_value.toInt(&number_ok); + break; + case 'c': + f_value = param_value.toFloat(&ok); + if (ok && f_value >= 0 && f_value <= 100) + cmyk.c = 0.01f * f_value; + break; + case 'm': + f_value = param_value.toFloat(&ok); + if (ok && f_value >= 0 && f_value <= 100) + cmyk.m = 0.01f * f_value; + break; + case 'y': + f_value = param_value.toFloat(&ok); + if (ok && f_value >= 0 && f_value <= 100) + cmyk.y = 0.01f * f_value; + break; + case 'k': + f_value = param_value.toFloat(&ok); + if (ok && f_value >= 0 && f_value <= 100) + cmyk.k = 0.01f * f_value; + break; + case 'o': + i_value = param_value.toInt(&ok); + if (ok) + overprinting = i_value; + break; + case 't': + f_value = param_value.toFloat(&ok); + if (ok && f_value >= 0.f && f_value <= 100.f) + opacity = 0.01f * f_value; + break; + default: + ; // nothing + } + i = next_i; + } + + if (!number_ok) + return nullptr; + + int color_pos = map->getNumColors(); + MapColor* color = new MapColor(name, color_pos); + color->setCmyk(cmyk); + color->setKnockout(!overprinting); + color->setOpacity(opacity); + map->addColor(color, color_pos); + color_index[number] = color; + + return color; +} + +namespace { + quint16 symbolType(const OcdFile::SymbolIndex::iterator& t) + { + if (t->type == Ocd::SymbolTypeLine && t->type2 == 1) + return Ocd::SymbolTypeLineText; + return t->type; + } + + template< class T > + quint8 symbolType(const T& t) + { + return t->type; + } +} + +template< class F > +void OcdFileImport::importSymbols(const OcdFile< F >& file) +{ + auto ocd_version = file.header()->version; + for (typename OcdFile< F >::SymbolIndex::iterator it = file.symbols().begin(); it != file.symbols().end(); ++it) + { + // When extra symbols are created, we want to insert the main symbol + // before them. That is why pos needs to be determined first. + auto pos = map->getNumSymbols(); + + Symbol* symbol = nullptr; + switch (symbolType(it)) + { + case Ocd::SymbolTypePoint: + symbol = importPointSymbol((const typename F::PointSymbol&)*it, ocd_version); + break; + case Ocd::SymbolTypeLine: + symbol = importLineSymbol((const typename F::LineSymbol&)*it, ocd_version); + break; + case Ocd::SymbolTypeArea: + symbol = importAreaSymbol((const typename F::AreaSymbol&)*it, ocd_version); + break; + case Ocd::SymbolTypeText: + symbol = importTextSymbol((const typename F::TextSymbol&)*it, ocd_version); + break; + case Ocd::SymbolTypeRectangle_V8: + case Ocd::SymbolTypeRectangle_V9: + symbol = importRectangleSymbol((const typename F::RectangleSymbol&)*it); + break; + case Ocd::SymbolTypeLineText: + symbol = importLineTextSymbol((const typename F::LineTextSymbol&)*it, ocd_version); + break; + default: + addWarning(tr("Unable to import symbol %1.%2 \"%3\": %4") . + arg(it->number / F::BaseSymbol::symbol_number_factor) . + arg(it->number % F::BaseSymbol::symbol_number_factor) . + arg(convertOcdString(it->description)). + arg(tr("Unsupported type \"%1\".").arg(it->type)) ); + continue; + } + + map->addSymbol(symbol, pos); + symbol_index[it->number] = symbol; + } +} + + +void OcdFileImport::importObjects(const OcdFile& file) +{ + auto ocd_version = file.header()->version; + MapPart* part = map->getCurrentPart(); + Q_ASSERT(part); + + for (const auto& object_entry : file.objects()) + { + if (object_entry.symbol) + { + if (auto object = importObject(file[object_entry], part, ocd_version)) + part->addObject(object, part->getNumObjects()); + } + } +} + +template< class F > +void OcdFileImport::importObjects(const OcdFile< F >& file) +{ + auto ocd_version = file.header()->version; + MapPart* part = map->getCurrentPart(); + Q_ASSERT(part); + + for (const auto& object_entry : file.objects()) + { + if ( object_entry.symbol + && object_entry.status != Ocd::ObjectDeleted + && object_entry.status != Ocd::ObjectDeletedForUndo ) + { + if (auto object = importObject(file[object_entry], part, ocd_version)) + part->addObject(object, part->getNumObjects()); + } + } +} + + +template< class F > +void OcdFileImport::importTemplates(const OcdFile< F >& file) +{ + for (auto&& string : file.strings()) + { + if (string.type == 8) + { + importTemplate(convertOcdString< typename F::Encoding >(file[string]), file.header()->version); + } + } +} + +Template* OcdFileImport::importTemplate(const QString& param_string, const int ocd_version) +{ + const QChar* unicode = param_string.unicode(); + + int i = param_string.indexOf(QLatin1Char('\t'), 0); + const QString filename = QString::fromRawData(unicode, qMax(-1, i)); + const QString clean_path = QDir::cleanPath(QString(filename).replace(QLatin1Char('\\'), QLatin1Char('/'))); + const QString extension = QFileInfo(clean_path).suffix().toLower(); + + Template* templ = nullptr; + if (extension.compare(QLatin1String("ocd")) == 0) + { + templ = new TemplateMap(clean_path, map); + } + else if (QImageReader::supportedImageFormats().contains(extension.toLatin1())) + { + templ = new TemplateImage(clean_path, map); + } + else + { + addWarning(tr("Unable to import template: \"%1\" is not a supported template type.").arg(filename)); + return nullptr; + } + + // 8 or 9 or 10 ? Only tested with 8 and 11 + double scale_factor = (ocd_version <= 8) ? 0.01 : 1.0; + unsigned int num_rotation_params = 0; + double rotation = 0.0; + double scale_x = 1.0; + double scale_y = 1.0; + int dimming = 0; + bool visible = false; + + while (i >= 0) + { + double value; + bool ok; + int next_i = param_string.indexOf(QLatin1Char('\t'), i+1); + int len = (next_i > 0 ? next_i : param_string.length()) - i - 2; + const QString param_value = QString::fromRawData(unicode+i+2, len); // no copying! + switch (param_string[i+1].toLatin1()) + { + case '\t': + // empty item + break; + case 'x': + value = param_value.toDouble(&ok); + if (ok) + templ->setTemplateX(qRound64(value*1000*scale_factor)); + break; + case 'y': + value = param_value.toDouble(&ok); + if (ok) + templ->setTemplateY(-qRound64(value*1000*scale_factor)); + break; + case 'a': + case 'b': + // TODO: use the distinct angles correctly, not just the average + rotation += param_value.toDouble(&ok); + if (ok) + ++num_rotation_params; + break; + case 'u': + value = param_value.toDouble(&ok); + if (ok && qAbs(value) >= 0.0000000001) + scale_x = value; + break; + case 'v': + value = param_value.toDouble(&ok); + if (ok && qAbs(value) >= 0.0000000001) + scale_y = value; + break; + case 'd': + dimming = param_value.toInt(); + break; + case 's': + visible = param_value.toInt(); + break; + default: + ; // nothing + } + i = next_i; + } + + if (num_rotation_params) + templ->setTemplateRotation(Georeferencing::degToRad(rotation / num_rotation_params)); + + templ->setTemplateScaleX(scale_x * scale_factor); + templ->setTemplateScaleY(scale_y * scale_factor); + + int template_pos = map->getFirstFrontTemplate(); + map->addTemplate(templ, 0, view); + map->setFirstFrontTemplate(template_pos+1); + + if (view) + { + TemplateVisibility* visibility = view->getTemplateVisibility(templ); + visibility->opacity = qMax(0.0, qMin(1.0, 0.01 * (100 - dimming))); + visibility->visible = visible; + } + + return templ; +} + + +void OcdFileImport::importExtras(const OcdFile& file) +{ + const Ocd::FileHeaderV8* header = file.header(); + map->setMapNotes(convertOcdString< Ocd::FormatV8::Encoding >(file.byteArray().data() + header->info_pos, header->info_size)); +} + +template< class F > +void OcdFileImport::importExtras(const OcdFile< F >& file) +{ + QString notes; + + for (auto&& string : file.strings()) + { + switch (string.type) + { + case 11: + // OCD 9, 10 + notes.append(convertOcdString< typename F::Encoding >(file[string])); + notes.append(QLatin1Char('\n')); + break; + case 1061: + // OCD 11 + notes.append(convertOcdString< typename F::Encoding >(file[string])); + break; + default: + ; // nothing + } + } + + map->setMapNotes(notes); +} + + +void OcdFileImport::importView(const OcdFile& file) +{ + if (view) + { + const Ocd::FileHeaderV8* header = file.header(); + const Ocd::SetupV8* setup = reinterpret_cast< const Ocd::SetupV8* >(file.byteArray().data() + header->setup_pos); + + if (setup->zoom >= MapView::zoom_out_limit && setup->zoom <= MapView::zoom_in_limit) + view->setZoom(setup->zoom); + + view->setCenter(convertOcdPoint(setup->center)); + } +} + +template< class F > +void OcdFileImport::importView(const OcdFile< F >& file) +{ + for (auto&& string : file.strings()) + { + if (string.type == 1030) + { + importView(convertOcdString< typename F::Encoding >(file[string])); + break; + } + } +} + +void OcdFileImport::importView(const QString& param_string) +{ + const QChar* unicode = param_string.unicode(); + + bool zoom_ok = false; + double zoom=1.0, offset_x=0.0, offset_y=0.0; + + int i = param_string.indexOf(QLatin1Char('\t'), 0); + ; // skip first word for this entry type + while (i >= 0) + { + int next_i = param_string.indexOf(QLatin1Char('\t'), i+1); + int len = (next_i > 0 ? next_i : param_string.length()) - i - 2; + const QString param_value = QString::fromRawData(unicode+i+2, len); // no copying! + switch (param_string[i+1].toLatin1()) + { + case '\t': + // empty item + break; + case 'x': + { + offset_x = param_value.toDouble(); + break; + } + case 'y': + { + offset_y = param_value.toDouble(); + break; + } + case 'z': + { + zoom = param_value.toDouble(&zoom_ok); + break; + } + default: + ; // nothing + } + i = next_i; + } + + if (view) + { + view->setCenter(MapCoord(offset_x, -offset_y)); + if (zoom_ok) + { + view->setZoom(zoom); + } + } +} + + +template< class S > +void OcdFileImport::setupBaseSymbol(Symbol* symbol, const S& ocd_symbol) +{ + typedef typename S::BaseSymbol BaseSymbol; + const BaseSymbol& base_symbol = ocd_symbol.base; + // common fields are name, number, description, helper_symbol, hidden/protected status + symbol->setName(convertOcdString(base_symbol.description)); + symbol->setNumberComponent(0, base_symbol.number / BaseSymbol::symbol_number_factor); + symbol->setNumberComponent(1, base_symbol.number % BaseSymbol::symbol_number_factor); + symbol->setNumberComponent(2, -1); + symbol->setIsHelperSymbol(false); + symbol->setProtected(base_symbol.status & Ocd::SymbolProtected); + symbol->setHidden(base_symbol.status & Ocd::SymbolHidden); +} + +template< class S > +PointSymbol* OcdFileImport::importPointSymbol(const S& ocd_symbol, int ocd_version) +{ + OcdImportedPointSymbol* symbol = new OcdImportedPointSymbol(); + setupBaseSymbol(symbol, ocd_symbol); + setupPointSymbolPattern(symbol, ocd_symbol.data_size, ocd_symbol.begin_of_elements, ocd_version); + symbol->setRotatable(ocd_symbol.base.flags & 1); + return symbol; +} + +template< class S > +Symbol* OcdFileImport::importLineSymbol(const S& ocd_symbol, int ocd_version) +{ + using LineStyle = Ocd::LineSymbolCommonV8; + + OcdImportedLineSymbol* line_for_borders = nullptr; + + // Import a main line? + OcdImportedLineSymbol* main_line = nullptr; + if (ocd_symbol.common.double_mode == 0 || ocd_symbol.common.line_width > 0) + { + main_line = importLineSymbolBase(ocd_symbol.common); + setupBaseSymbol(main_line, ocd_symbol); + line_for_borders = main_line; + } + + // Import a 'framing' line? + OcdImportedLineSymbol* framing_line = nullptr; + if (ocd_symbol.common.framing_width > 0 && ocd_version >= 7) + { + framing_line = importLineSymbolFraming(ocd_symbol.common, main_line); + setupBaseSymbol(framing_line, ocd_symbol); + if (!line_for_borders) + line_for_borders = framing_line; + } + + // Import a 'double' line? + bool has_border_line = + (ocd_symbol.common.double_mode != 0) && + (ocd_symbol.common.double_left_width > 0 || ocd_symbol.common.double_right_width > 0); + OcdImportedLineSymbol *double_line = nullptr; + if ( has_border_line && + (ocd_symbol.common.double_flags & LineStyle::DoubleFillColorOn || !line_for_borders) ) + { + double_line = importLineSymbolDoubleBorder(ocd_symbol.common); + setupBaseSymbol(double_line, ocd_symbol); + line_for_borders = double_line; + } + + // Border lines + if (has_border_line) + { + Q_ASSERT(line_for_borders); + setupLineSymbolForBorder(line_for_borders, ocd_symbol.common); + } + + // Create point symbols along line; middle ("normal") dash, corners, start, and end. + OcdImportedLineSymbol* symbol_line = main_line ? main_line : double_line; // Find the line to attach the symbols to + if (symbol_line == nullptr) + { + main_line = new OcdImportedLineSymbol(); + symbol_line = main_line; + setupBaseSymbol(main_line, ocd_symbol); + + main_line->segment_length = convertLength(ocd_symbol.common.main_length); + main_line->end_length = convertLength(ocd_symbol.common.end_length); + } + + setupLineSymbolPointSymbol(symbol_line, ocd_symbol.common, ocd_symbol.begin_of_elements, ocd_version); + + // TODO: taper fields (tmode and tlast) + + if (main_line == nullptr && framing_line == nullptr) + { + return double_line; + } + else if (double_line == nullptr && framing_line == nullptr) + { + return main_line; + } + else if (main_line == nullptr && double_line == nullptr) + { + return framing_line; + } + else + { + CombinedSymbol* full_line = new CombinedSymbol(); + setupBaseSymbol(full_line, ocd_symbol); + mergeLineSymbol(full_line, main_line, framing_line, double_line); + addSymbolWarning(symbol_line, tr("This symbol cannot be saved as a proper OCD symbol again.")); + return full_line; + } +} + +OcdFileImport::OcdImportedLineSymbol* OcdFileImport::importLineSymbolBase(const Ocd::LineSymbolCommonV8& attributes) +{ + using LineStyle = Ocd::LineSymbolCommonV8; + + // Basic line options + auto symbol = new OcdImportedLineSymbol(); + symbol->line_width = convertLength(attributes.line_width); + symbol->color = convertColor(attributes.line_color); + + // Cap and join styles + switch (attributes.line_style) + { + default: + addSymbolWarning( symbol, + tr("Unsupported line style '%1'."). + arg(attributes.line_style) ); + // fall through + case LineStyle::BevelJoin_FlatCap: + symbol->join_style = LineSymbol::BevelJoin; + symbol->cap_style = LineSymbol::FlatCap; + break; + case LineStyle::RoundJoin_RoundCap: + symbol->join_style = LineSymbol::RoundJoin; + symbol->cap_style = LineSymbol::RoundCap; + break; + case LineStyle::BevelJoin_PointedCap: + symbol->join_style = LineSymbol::BevelJoin; + symbol->cap_style = LineSymbol::PointedCap; + break; + case LineStyle::RoundJoin_PointedCap: + symbol->join_style = LineSymbol::RoundJoin; + symbol->cap_style = LineSymbol::PointedCap; + break; + case LineStyle::MiterJoin_FlatCap: + symbol->join_style = LineSymbol::MiterJoin; + symbol->cap_style = LineSymbol::FlatCap; + break; + case LineStyle::MiterJoin_PointedCap: + symbol->join_style = LineSymbol::MiterJoin; + symbol->cap_style = LineSymbol::PointedCap; + break; + } + + if (symbol->cap_style == LineSymbol::PointedCap) + { + int ocd_length = attributes.dist_from_start; + if (attributes.dist_from_start != attributes.dist_from_end) + { + // FIXME: Different lengths for start and end length of pointed line ends are not supported yet, so take the average + ocd_length = (attributes.dist_from_start + attributes.dist_from_end) / 2; + addSymbolWarning( symbol, + tr("Different lengths for pointed caps at begin (%1 mm) and end (%2 mm) are not supported. Using %3 mm."). + arg(locale.toString(0.001f * convertLength(attributes.dist_from_start))). + arg(locale.toString(0.001f * convertLength(attributes.dist_from_end))). + arg(locale.toString(0.001f * convertLength(ocd_length))) ); + } + symbol->pointed_cap_length = convertLength(ocd_length); + symbol->join_style = LineSymbol::RoundJoin; // NOTE: while the setting may be different (see what is set in the first place), OC*D always draws round joins if the line cap is pointed! + } + + // Handle the dash pattern + if (attributes.main_gap || attributes.sec_gap) + { + if (!attributes.main_length) + { + // Invalid dash pattern + addSymbolWarning( symbol, + tr("The dash pattern cannot be imported correctly.") ); + } + else if (attributes.sec_gap && !attributes.main_gap) + { + // Special case main_gap == 0 + symbol->dashed = true; + symbol->dash_length = convertLength(attributes.main_length - attributes.sec_gap); + symbol->break_length = convertLength(attributes.sec_gap); + + if (attributes.end_length) + { + if (qAbs((qint32)attributes.main_length - 2*attributes.end_length) > 1) + { + // End length not equal to 0.5 * main length + addSymbolWarning( symbol, + tr("The dash pattern's end length (%1 mm) cannot be imported correctly. Using %2 mm."). + arg(locale.toString(0.001f * convertLength(attributes.end_length))). + arg(locale.toString(0.001f * symbol->dash_length)) ); + } + if (attributes.end_gap) + { + addSymbolWarning( symbol, + tr("The dash pattern's end gap (%1 mm) cannot be imported correctly. Using %2 mm."). + arg(locale.toString(0.001f * convertLength(attributes.end_gap))). + arg(locale.toString(0.001f * symbol->break_length)) ); + } + } + } + else + { + // Standard case + symbol->dashed = true; + symbol->dash_length = convertLength(attributes.main_length); + symbol->break_length = convertLength(attributes.main_gap); + + if (attributes.end_length && attributes.end_length != attributes.main_length) + { + if (attributes.main_length && 0.75 >= attributes.end_length / attributes.main_length) + { + // End length max. 75 % of main length + symbol->half_outer_dashes = true; + } + + if (qAbs((qint32)attributes.main_length - 2*attributes.end_length) > 1) + { + // End length not equal to 0.5 * main length + addSymbolWarning( symbol, + tr("The dash pattern's end length (%1 mm) cannot be imported correctly. Using %2 mm."). + arg(locale.toString(0.001f * convertLength(attributes.end_length))). + arg(locale.toString(0.001f * (symbol->half_outer_dashes ? (symbol->dash_length/2) : symbol->dash_length))) ); + } + } + + if (attributes.sec_gap) + { + symbol->dashes_in_group = 2; + symbol->in_group_break_length = convertLength(attributes.sec_gap); + symbol->dash_length = (symbol->dash_length - symbol->in_group_break_length) / 2; + + if (attributes.end_length && attributes.end_gap != attributes.sec_gap) + { + addSymbolWarning( symbol, + tr("The dash pattern's end gap (%1 mm) cannot be imported correctly. Using %2 mm."). + arg(locale.toString(0.001f * convertLength(attributes.end_gap))). + arg(locale.toString(0.001f * symbol->in_group_break_length)) ); + } + } + } + } + else + { + symbol->segment_length = convertLength(attributes.main_length); + symbol->end_length = convertLength(attributes.end_length); + } + + return symbol; +} + +OcdFileImport::OcdImportedLineSymbol* OcdFileImport::importLineSymbolFraming(const Ocd::LineSymbolCommonV8& attributes, const LineSymbol* main_line) +{ + using LineStyle = Ocd::LineSymbolCommonV8; + + // Basic line options + auto framing_line = new OcdImportedLineSymbol(); + framing_line->line_width = convertLength(attributes.framing_width); + framing_line->color = convertColor(attributes.framing_color); + + // Cap and join styles + switch (attributes.framing_style) + { + case LineStyle::BevelJoin_FlatCap: + framing_line->join_style = LineSymbol::BevelJoin; + framing_line->cap_style = LineSymbol::FlatCap; + break; + case LineStyle::RoundJoin_RoundCap: + framing_line->join_style = LineSymbol::RoundJoin; + framing_line->cap_style = LineSymbol::RoundCap; + break; + case LineStyle::MiterJoin_FlatCap: + framing_line->join_style = LineSymbol::MiterJoin; + framing_line->cap_style = LineSymbol::FlatCap; + break; + default: + addSymbolWarning( main_line, + tr("Unsupported framing line style '%1'."). + arg(attributes.line_style) ); + } + + return framing_line; +} + +OcdFileImport::OcdImportedLineSymbol* OcdFileImport::importLineSymbolDoubleBorder(const Ocd::LineSymbolCommonV8& attributes) +{ + using LineStyle = Ocd::LineSymbolCommonV8; + + auto double_line = new OcdImportedLineSymbol(); + double_line->line_width = convertLength(attributes.double_width); + double_line->cap_style = LineSymbol::FlatCap; + double_line->join_style = LineSymbol::MiterJoin; + double_line->segment_length = convertLength(attributes.main_length); + double_line->end_length = convertLength(attributes.end_length); + + if (attributes.double_flags & LineStyle::DoubleFillColorOn) + double_line->color = convertColor(attributes.double_color); + else + double_line->color = nullptr; + + return double_line; +} + +void OcdFileImport::setupLineSymbolForBorder(OcdFileImport::OcdImportedLineSymbol* line_for_borders, const Ocd::LineSymbolCommonV8& attributes) +{ + line_for_borders->have_border_lines = true; + LineSymbolBorder& border = line_for_borders->getBorder(); + LineSymbolBorder& right_border = line_for_borders->getRightBorder(); + + // Border color and width + border.color = convertColor(attributes.double_left_color); + border.width = convertLength(attributes.double_left_width); + border.shift = convertLength(attributes.double_left_width) / 2 + (convertLength(attributes.double_width) - line_for_borders->line_width) / 2; + + right_border.color = convertColor(attributes.double_right_color); + right_border.width = convertLength(attributes.double_right_width); + right_border.shift = convertLength(attributes.double_right_width) / 2 + (convertLength(attributes.double_width) - line_for_borders->line_width) / 2; + + // The borders may be dashed + if (attributes.double_gap > 0 && attributes.double_mode > 1) + { + border.dashed = true; + border.dash_length = convertLength(attributes.double_length); + border.break_length = convertLength(attributes.double_gap); + + // If ocd_symbol->dmode == 2, only the left border should be dashed + if (attributes.double_mode > 2) + { + right_border.dashed = border.dashed; + right_border.dash_length = border.dash_length; + right_border.break_length = border.break_length; + } + } +} + +void OcdFileImport::setupLineSymbolPointSymbol(OcdFileImport::OcdImportedLineSymbol* line_symbol, const Ocd::LineSymbolCommonV8& attributes, const Ocd::PointSymbolElementV8* elements, int ocd_version) +{ + const Ocd::OcdPoint32* coords = reinterpret_cast(elements); + + line_symbol->mid_symbols_per_spot = attributes.num_prim_sym; + line_symbol->mid_symbol_distance = convertLength(attributes.prim_sym_dist); + line_symbol->mid_symbol = new OcdImportedPointSymbol(); + setupPointSymbolPattern(line_symbol->mid_symbol, attributes.primary_data_size, elements, ocd_version); + coords += attributes.primary_data_size; + + if (attributes.secondary_data_size > 0) + { + //symbol_line->dash_symbol = importPattern( ocd_symbol->ssnpts, symbolptr); + coords += attributes.secondary_data_size; + addSymbolWarning(line_symbol, tr("Skipped secondary point symbol.")); + } + if (attributes.corner_data_size > 0) + { + line_symbol->dash_symbol = new OcdImportedPointSymbol(); + setupPointSymbolPattern(line_symbol->dash_symbol, attributes.corner_data_size, reinterpret_cast(coords), ocd_version); + line_symbol->dash_symbol->setName(LineSymbolSettings::tr("Dash symbol")); + coords += attributes.corner_data_size; + } + if (attributes.start_data_size > 0) + { + line_symbol->start_symbol = new OcdImportedPointSymbol(); + setupPointSymbolPattern(line_symbol->start_symbol, attributes.start_data_size, reinterpret_cast(coords), ocd_version); + line_symbol->start_symbol->setName(LineSymbolSettings::tr("Start symbol")); + coords += attributes.start_data_size; + } + if (attributes.end_data_size > 0) + { + line_symbol->end_symbol = new OcdImportedPointSymbol(); + setupPointSymbolPattern(line_symbol->end_symbol, attributes.end_data_size, reinterpret_cast(coords), ocd_version); + line_symbol->end_symbol->setName(LineSymbolSettings::tr("End symbol")); + } + + // FIXME: not really sure how this translates... need test cases + line_symbol->minimum_mid_symbol_count = 0; //1 + ocd_symbol->smin; + line_symbol->minimum_mid_symbol_count_when_closed = 0; //1 + ocd_symbol->smin; + line_symbol->show_at_least_one_symbol = false; // NOTE: this works in a different way than OC*D's 'at least X symbols' setting (per-segment instead of per-object) + + // Suppress dash symbol at line ends if both start symbol and end symbol exist, + // but don't create a warning unless a dash symbol is actually defined + // and the line symbol is not Mapper's 799 Simple orienteering course. + if (line_symbol->start_symbol && line_symbol->end_symbol) + { + line_symbol->setSuppressDashSymbolAtLineEnds(true); + if (line_symbol->dash_symbol && line_symbol->number[0] != 799) + { + addSymbolWarning(line_symbol, tr("Suppressing dash symbol at line ends.")); + } + } +} + +void OcdFileImport::mergeLineSymbol(CombinedSymbol* full_line, LineSymbol* main_line, LineSymbol* framing_line, LineSymbol* double_line) +{ + full_line->setNumParts(3); // reserve + int part = 0; + if (main_line) + { + full_line->setPart(part++, main_line, true); + main_line->setHidden(false); + main_line->setProtected(false); + } + if (double_line) + { + full_line->setPart(part++, double_line, true); + double_line->setHidden(false); + double_line->setProtected(false); + } + if (framing_line) + { + full_line->setPart(part++, framing_line, true); + framing_line->setHidden(false); + framing_line->setProtected(false); + } + full_line->setNumParts(part); +} + +AreaSymbol* OcdFileImport::importAreaSymbol(const Ocd::AreaSymbolV8& ocd_symbol, int ocd_version) +{ + Q_ASSERT(ocd_version <= 8); + OcdImportedAreaSymbol* symbol = new OcdImportedAreaSymbol(); + setupBaseSymbol(symbol, ocd_symbol); + setupAreaSymbolCommon( + symbol, + ocd_symbol.fill_on, + ocd_symbol.common, + ocd_symbol.data_size, + ocd_symbol.begin_of_elements, + ocd_version); + return symbol; +} + +template< class S > +AreaSymbol* OcdFileImport::importAreaSymbol(const S& ocd_symbol, int ocd_version) +{ + Q_ASSERT(ocd_version >= 8); + OcdImportedAreaSymbol* symbol = new OcdImportedAreaSymbol(); + setupBaseSymbol(symbol, ocd_symbol); + setupAreaSymbolCommon( + symbol, + ocd_symbol.common.fill_on_V9, + ocd_symbol.common, + ocd_symbol.data_size, + ocd_symbol.begin_of_elements, + ocd_version); + return symbol; +} + +void OcdFileImport::setupAreaSymbolCommon(OcdImportedAreaSymbol* symbol, bool fill_on, const Ocd::AreaSymbolCommonV8& ocd_symbol, std::size_t data_size, const Ocd::PointSymbolElementV8* elements, int ocd_version) +{ + // Basic area symbol fields: minimum_area, color + symbol->minimum_area = 0; + symbol->color = fill_on ? convertColor(ocd_symbol.fill_color) : nullptr; + symbol->patterns.clear(); + symbol->patterns.reserve(4); + + // Hatching + if (ocd_symbol.hatch_mode != Ocd::HatchNone) + { + AreaSymbol::FillPattern pattern; + pattern.type = AreaSymbol::FillPattern::LinePattern; + pattern.angle = convertAngle(ocd_symbol.hatch_angle_1); + pattern.rotatable = true; + pattern.line_spacing = convertLength(ocd_symbol.hatch_dist); + pattern.line_offset = 0; + pattern.line_color = convertColor(ocd_symbol.hatch_color); + pattern.line_width = convertLength(ocd_symbol.hatch_line_width); + if (ocd_version <= 8) + { + pattern.line_spacing += pattern.line_width; + } + symbol->patterns.push_back(pattern); + + if (ocd_symbol.hatch_mode == Ocd::HatchCross) + { + // Second hatch, same as the first, just a different angle + pattern.angle = convertAngle(ocd_symbol.hatch_angle_2); + symbol->patterns.push_back(pattern); + } + } + + if (ocd_symbol.structure_mode != Ocd::StructureNone) + { + AreaSymbol::FillPattern pattern; + pattern.type = AreaSymbol::FillPattern::PointPattern; + pattern.angle = convertAngle(ocd_symbol.structure_angle); + pattern.rotatable = true; + pattern.point_distance = convertLength(ocd_symbol.structure_width); + pattern.line_spacing = convertLength(ocd_symbol.structure_height); + pattern.line_offset = 0; + pattern.offset_along_line = 0; + // FIXME: somebody needs to own this symbol and be responsible for deleting it + // Right now it looks like a potential memory leak + pattern.point = new OcdImportedPointSymbol(); + setupPointSymbolPattern(pattern.point, data_size, elements, ocd_version); + + // OC*D 8 has a "staggered" pattern mode, where successive rows are shifted width/2 relative + // to each other. We need to simulate this in Mapper with two overlapping patterns, each with + // twice the height. The second is then offset by width/2, height/2. + if (ocd_symbol.structure_mode == Ocd::StructureShiftedRows) + { + pattern.line_spacing *= 2; + symbol->patterns.push_back(pattern); + + pattern.line_offset = pattern.line_spacing / 2; + pattern.offset_along_line = pattern.point_distance / 2; + pattern.point = pattern.point->duplicate()->asPoint(); + } + symbol->patterns.push_back(pattern); + } +} + +template< class S > +TextSymbol* OcdFileImport::importTextSymbol(const S& ocd_symbol, int /*ocd_version*/) +{ + OcdImportedTextSymbol* symbol = new OcdImportedTextSymbol(); + setupBaseSymbol(symbol, ocd_symbol); + setBasicAttributes(symbol, convertOcdString(ocd_symbol.font_name), ocd_symbol.basic); + setSpecialAttributes(symbol, ocd_symbol.special); + setFraming(symbol, ocd_symbol.framing); + return symbol; +} + +template< class S > +TextSymbol* OcdFileImport::importLineTextSymbol(const S& ocd_symbol, int /*ocd_version*/) +{ + OcdImportedTextSymbol* symbol = new OcdImportedTextSymbol(); + setupBaseSymbol(symbol, ocd_symbol); + setBasicAttributes(symbol, convertOcdString(ocd_symbol.font_name), ocd_symbol.basic); + setFraming(symbol, ocd_symbol.framing); + + addSymbolWarning(symbol, tr("Line text symbols are not yet supported. Marking the symbol as hidden.")); + symbol->setHidden(true); + return symbol; +} + +template< class S > +LineSymbol* OcdFileImport::importRectangleSymbol(const S& ocd_symbol) +{ + OcdImportedLineSymbol* symbol = new OcdImportedLineSymbol(); + setupBaseSymbol(symbol, ocd_symbol); + + symbol->line_width = convertLength(ocd_symbol.line_width); + symbol->color = convertColor(ocd_symbol.line_color); + symbol->cap_style = LineSymbol::RoundCap; + symbol->join_style = LineSymbol::RoundJoin; + + RectangleInfo rect; + rect.border_line = symbol; + rect.corner_radius = 0.001 * convertLength(ocd_symbol.corner_radius); + rect.has_grid = ocd_symbol.grid_flags & 1; + + if (rect.has_grid) + { + OcdImportedLineSymbol* inner_line = new OcdImportedLineSymbol(); + setupBaseSymbol(inner_line, ocd_symbol); + inner_line->setNumberComponent(2, 1); // TODO: Dynamic + inner_line->line_width = qRound(1000 * 0.15); + inner_line->color = symbol->color; + map->addSymbol(inner_line, map->getNumSymbols()); + + OcdImportedTextSymbol* text = new OcdImportedTextSymbol(); + setupBaseSymbol(text, ocd_symbol); + text->setNumberComponent(2, 2); // TODO: Dynamic + text->font_family = QString::fromLatin1("Arial"); + text->font_size = qRound(1000 * (15 / 72.0 * 25.4)); + text->color = symbol->color; + text->bold = true; + text->updateQFont(); + map->addSymbol(text, map->getNumSymbols()); + + rect.inner_line = inner_line; + rect.text = text; + rect.number_from_bottom = ocd_symbol.grid_flags & 2; + rect.cell_width = 0.001 * convertLength(ocd_symbol.cell_width); + rect.cell_height = 0.001 * convertLength(ocd_symbol.cell_height); + rect.unnumbered_cells = ocd_symbol.unnumbered_cells; + rect.unnumbered_text = convertOcdString(ocd_symbol.unnumbered_text); + } + rectangle_info.insert(ocd_symbol.base.number, rect); + + return symbol; +} + +void OcdFileImport::setupPointSymbolPattern(PointSymbol* symbol, std::size_t data_size, const Ocd::PointSymbolElementV8* elements, int version) +{ + Q_ASSERT(symbol != nullptr); + + symbol->setRotatable(true); + bool base_symbol_used = false; + + for (std::size_t i = 0; i < data_size; i += 2) + { + const Ocd::PointSymbolElementV8* element = reinterpret_cast(&reinterpret_cast(elements)[i]); + const Ocd::OcdPoint32* const coords = reinterpret_cast(elements) + i + 2; + switch (element->type) + { + case Ocd::PointSymbolElementV8::TypeDot: + if (element->diameter > 0) + { + bool can_use_base_symbol = (!base_symbol_used && (!element->num_coords || (!coords[0].x && !coords[0].y))); + PointSymbol* working_symbol = can_use_base_symbol ? symbol : new PointSymbol(); + working_symbol->setInnerColor(convertColor(element->color)); + working_symbol->setInnerRadius(convertLength(element->diameter) / 2); + working_symbol->setOuterColor(nullptr); + working_symbol->setOuterWidth(0); + if (can_use_base_symbol) + { + base_symbol_used = true; + } + else + { + working_symbol->setRotatable(false); + PointObject* element_object = new PointObject(working_symbol); + if (element->num_coords) + { + const MapCoord coord = convertOcdPoint(coords[0]); + element_object->setPosition(coord.nativeX(), coord.nativeY()); + } + symbol->addElement(symbol->getNumElements(), element_object, working_symbol); + } + } + break; + case Ocd::PointSymbolElementV8::TypeCircle: + { + int element_radius = (version <= 8) ? (element->diameter / 2 - element->line_width) + : ((element->diameter - element->line_width) / 2); + if (element_radius > 0 && element->line_width > 0) + { + bool can_use_base_symbol = (!base_symbol_used && (!element->num_coords || (!coords[0].x && !coords[0].y))); + PointSymbol* working_symbol = can_use_base_symbol ? symbol : new PointSymbol(); + working_symbol->setInnerColor(nullptr); + working_symbol->setInnerRadius(convertLength(element_radius)); + working_symbol->setOuterColor(convertColor(element->color)); + working_symbol->setOuterWidth(convertLength(element->line_width)); + if (can_use_base_symbol) + { + base_symbol_used = true; + } + else + { + working_symbol->setRotatable(false); + PointObject* element_object = new PointObject(working_symbol); + if (element->num_coords) + { + const MapCoord coord = convertOcdPoint(coords[0]); + element_object->setPosition(coord.nativeX(), coord.nativeY()); + } + symbol->addElement(symbol->getNumElements(), element_object, working_symbol); + } + } + break; + } + case Ocd::PointSymbolElementV8::TypeLine: + if (element->line_width > 0) + { + OcdImportedLineSymbol* element_symbol = new OcdImportedLineSymbol(); + element_symbol->line_width = convertLength(element->line_width); + element_symbol->color = convertColor(element->color); + OcdImportedPathObject* element_object = new OcdImportedPathObject(element_symbol); + fillPathCoords(element_object, false, element->num_coords, coords); + element_object->recalculateParts(); + symbol->addElement(symbol->getNumElements(), element_object, element_symbol); + } + break; + case Ocd::PointSymbolElementV8::TypeArea: + { + OcdImportedAreaSymbol* element_symbol = new OcdImportedAreaSymbol(); + element_symbol->color = convertColor(element->color); + OcdImportedPathObject* element_object = new OcdImportedPathObject(element_symbol); + fillPathCoords(element_object, true, element->num_coords, coords); + element_object->recalculateParts(); + symbol->addElement(symbol->getNumElements(), element_object, element_symbol); + } + break; + default: + ; // TODO: not-supported warning + } + i += element->num_coords; + } +} + +template< class O > +Object* OcdFileImport::importObject(const O& ocd_object, MapPart* part, int ocd_version) +{ + Symbol* symbol = nullptr; + if (ocd_object.symbol >= 0) + { + symbol = symbol_index[ocd_object.symbol]; + } + + if (!symbol) + { + switch (ocd_object.type) + { + case 1: + symbol = map->getUndefinedPoint(); + break; + case 2: + case 3: + symbol = map->getUndefinedLine(); + break; + case 4: + case 5: + symbol = map->getUndefinedText(); + break; + default: + addWarning(tr("Unable to load object")); + qDebug() << "Undefined object type" << ocd_object.type << " for object of symbol" << ocd_object.symbol; + return nullptr; + } + } + + if (symbol->getType() == Symbol::Line && rectangle_info.contains(ocd_object.symbol)) + { + Object* object = importRectangleObject(ocd_object, part, rectangle_info[ocd_object.symbol]); + if (!object) + addWarning(tr("Unable to import rectangle object")); + return object; + } + + if (symbol->getType() == Symbol::Point) + { + PointObject* p = new PointObject(); + p->setSymbol(symbol, true); + + // extra properties: rotation + PointSymbol* point_symbol = reinterpret_cast(symbol); + if (point_symbol->isRotatable()) + { + p->setRotation(convertAngle(ocd_object.angle)); + } + else if (ocd_object.angle != 0) + { + if (!point_symbol->isSymmetrical()) + { + point_symbol->setRotatable(true); + p->setRotation(convertAngle(ocd_object.angle)); + } + } + + const MapCoord pos = convertOcdPoint(ocd_object.coords[0]); + p->setPosition(pos.nativeX(), pos.nativeY()); + + p->setMap(map); + return p; + } + else if (symbol->getType() == Symbol::Text) + { + TextObject *t = new TextObject(symbol); + t->setText(getObjectText(ocd_object, ocd_version)); + t->setRotation(convertAngle(ocd_object.angle)); + t->setHorizontalAlignment(text_halign_map.value(symbol)); + // Vertical alignment is set in fillTextPathCoords(). + + // Text objects need special path translation + if (!fillTextPathCoords(t, reinterpret_cast(symbol), ocd_object.num_items, (Ocd::OcdPoint32 *)ocd_object.coords)) + { + addWarning(tr("Not importing text symbol, couldn't figure out path' (npts=%1): %2") + .arg(ocd_object.num_items).arg(t->getText())); + delete t; + return nullptr; + } + t->setMap(map); + return t; + } + else if (symbol->getType() == Symbol::Line || symbol->getType() == Symbol::Area || symbol->getType() == Symbol::Combined) + { + OcdImportedPathObject *p = new OcdImportedPathObject(symbol); + p->setPatternRotation(convertAngle(ocd_object.angle)); + + // Normal path + fillPathCoords(p, symbol->getType() == Symbol::Area, ocd_object.num_items, (Ocd::OcdPoint32*)ocd_object.coords); + p->recalculateParts(); + p->setMap(map); + return p; + } + + return nullptr; +} + +QString OcdFileImport::getObjectText(const Ocd::ObjectV8& ocd_object, int ocd_version) const +{ + QString object_text; + if (ocd_object.unicode && ocd_version >= 8) + { + object_text = convertOcdString((const QChar*)(ocd_object.coords + ocd_object.num_items)); + } + else + { + const size_t len = sizeof(Ocd::OcdPoint32) * ocd_object.num_text; + object_text = convertOcdString((const char*)(ocd_object.coords + ocd_object.num_items), len); + } + + // Remove leading "\r\n" + if (object_text.startsWith(QLatin1String("\r\n"))) + { + object_text.remove(0, 2); + } + + return object_text; +} + +template< class O > +inline +QString OcdFileImport::getObjectText(const O& ocd_object, int /*ocd_version*/) const +{ + auto data = (const QChar *)(ocd_object.coords + ocd_object.num_items); + if (data[0] == QLatin1Char{'\r'} && data[1] == QLatin1Char{'\n'}) + data += 2; + return QString(data); +} + + +template< class O > +Object* OcdFileImport::importRectangleObject(const O& ocd_object, MapPart* part, const OcdFileImport::RectangleInfo& rect) +{ + if (ocd_object.num_items != 4) + { + qDebug() << "importRectangleObject called with num_items =" << ocd_object.num_items << "for object of symbol" << ocd_object.symbol; + if (ocd_object.num_items != 5) // 5 coords are handled like 4 coords now + return nullptr; + } + return importRectangleObject(ocd_object.coords, part, rect); +} + +Object* OcdFileImport::importRectangleObject(const Ocd::OcdPoint32* ocd_points, MapPart* part, const OcdFileImport::RectangleInfo& rect) +{ + // Convert corner points + MapCoord bottom_left = convertOcdPoint(ocd_points[0]); + MapCoord bottom_right = convertOcdPoint(ocd_points[1]); + MapCoord top_right = convertOcdPoint(ocd_points[2]); + MapCoord top_left = convertOcdPoint(ocd_points[3]); + + MapCoordF top_left_f = MapCoordF(top_left); + MapCoordF top_right_f = MapCoordF(top_right); + MapCoordF bottom_left_f = MapCoordF(bottom_left); + MapCoordF bottom_right_f = MapCoordF(bottom_right); + MapCoordF right = MapCoordF(top_right.x() - top_left.x(), top_right.y() - top_left.y()); + double angle = right.angle(); + MapCoordF down = MapCoordF(bottom_left.x() - top_left.x(), bottom_left.y() - top_left.y()); + right.normalize(); + down.normalize(); + + // Create border line + MapCoordVector coords; + if (rect.corner_radius == 0) + { + coords.emplace_back(top_left); + coords.emplace_back(top_right); + coords.emplace_back(bottom_right); + coords.emplace_back(bottom_left); + } + else + { + double handle_radius = (1 - BEZIER_KAPPA) * rect.corner_radius; + coords.emplace_back(top_right_f - right * rect.corner_radius, MapCoord::CurveStart); + coords.emplace_back(top_right_f - right * handle_radius); + coords.emplace_back(top_right_f + down * handle_radius); + coords.emplace_back(top_right_f + down * rect.corner_radius); + coords.emplace_back(bottom_right_f - down * rect.corner_radius, MapCoord::CurveStart); + coords.emplace_back(bottom_right_f - down * handle_radius); + coords.emplace_back(bottom_right_f - right * handle_radius); + coords.emplace_back(bottom_right_f - right * rect.corner_radius); + coords.emplace_back(bottom_left_f + right * rect.corner_radius, MapCoord::CurveStart); + coords.emplace_back(bottom_left_f + right * handle_radius); + coords.emplace_back(bottom_left_f - down * handle_radius); + coords.emplace_back(bottom_left_f - down * rect.corner_radius); + coords.emplace_back(top_left_f + down * rect.corner_radius, MapCoord::CurveStart); + coords.emplace_back(top_left_f + down * handle_radius); + coords.emplace_back(top_left_f + right * handle_radius); + coords.emplace_back(top_left_f + right * rect.corner_radius); + } + PathObject *border_path = new PathObject(rect.border_line, coords, map); + border_path->parts().front().setClosed(true, false); + + if (rect.has_grid && rect.cell_width > 0 && rect.cell_height > 0) + { + // Calculate grid sizes + double width = top_left.distanceTo(top_right); + double height = top_left.distanceTo(bottom_left); + int num_cells_x = qMax(1, qRound(width / rect.cell_width)); + int num_cells_y = qMax(1, qRound(height / rect.cell_height)); + + float cell_width = width / num_cells_x; + float cell_height = height / num_cells_y; + + // Create grid lines + coords.resize(2); + for (int x = 1; x < num_cells_x; ++x) + { + coords[0] = MapCoord(top_left_f + x * cell_width * right); + coords[1] = MapCoord(bottom_left_f + x * cell_width * right); + + PathObject *path = new PathObject(rect.inner_line, coords, map); + part->addObject(path, part->getNumObjects()); + } + for (int y = 1; y < num_cells_y; ++y) + { + coords[0] = MapCoord(top_left_f + y * cell_height * down); + coords[1] = MapCoord(top_right_f + y * cell_height * down); + + PathObject *path = new PathObject(rect.inner_line, coords, map); + part->addObject(path, part->getNumObjects()); + } + + // Create grid text + if (height >= rect.cell_height / 2) + { + for (int y = 0; y < num_cells_y; ++y) + { + for (int x = 0; x < num_cells_x; ++x) + { + int cell_num; + QString cell_text; + + if (rect.number_from_bottom) + cell_num = y * num_cells_x + x + 1; + else + cell_num = (num_cells_y - 1 - y) * num_cells_x + x + 1; + + if (cell_num > num_cells_x * num_cells_y - rect.unnumbered_cells) + cell_text = rect.unnumbered_text; + else + cell_text = QString::number(cell_num); + + TextObject* object = new TextObject(rect.text); + object->setMap(map); + object->setText(cell_text); + object->setRotation(-angle); + object->setHorizontalAlignment(TextObject::AlignLeft); + object->setVerticalAlignment(TextObject::AlignTop); + double position_x = (x + 0.07f) * cell_width; + double position_y = (y + 0.04f) * cell_height + rect.text->getFontMetrics().ascent() / rect.text->calculateInternalScaling() - rect.text->getFontSize(); + object->setAnchorPosition(top_left_f + position_x * right + position_y * down); + part->addObject(object, part->getNumObjects()); + + //pts[0].Y -= rectinfo.gridText.FontAscent - rectinfo.gridText.FontEmHeight; + } + } + } + } + + return border_path; +} + +void OcdFileImport::setPathHolePoint(OcdImportedPathObject *object, int pos) +{ + // Look for curve start points before the current point and apply hole point only if no such point is there. + // This prevents hole points in the middle of a curve caused by incorrect map objects. + if (pos >= 1 && object->coords[pos].isCurveStart()) + ; //object->coords[i-1].setHolePoint(true); + else if (pos >= 2 && object->coords[pos-1].isCurveStart()) + ; //object->coords[i-2].setHolePoint(true); + else if (pos >= 3 && object->coords[pos-2].isCurveStart()) + ; //object->coords[i-3].setHolePoint(true); + else if (pos > 0) // Don't start with hole point. + object->coords[pos].setHolePoint(true); +} + +void OcdFileImport::setPointFlags(OcdImportedPathObject* object, quint16 pos, bool is_area, const Ocd::OcdPoint32& ocd_point) +{ + // We can support CurveStart, HolePoint, DashPoint. + // CurveStart needs to be applied to the main point though, not the control point, and + // hole points need to bet set as the last point of a part of an area object instead of the first point of the next part + if (ocd_point.x & Ocd::OcdPoint32::FlagCtl1 && pos > 0) + object->coords[pos-1].setCurveStart(true); + if ((ocd_point.y & Ocd::OcdPoint32::FlagDash) || (ocd_point.y & Ocd::OcdPoint32::FlagCorner)) + object->coords[pos].setDashPoint(true); + if (ocd_point.y & Ocd::OcdPoint32::FlagHole) + setPathHolePoint(object, is_area ? (pos - 1) : pos); +} + +/** Translates the OC*D path given in the last two arguments into an Object. + */ +void OcdFileImport::fillPathCoords(OcdImportedPathObject *object, bool is_area, quint16 num_points, const Ocd::OcdPoint32* ocd_points) +{ + object->coords.resize(num_points); + for (int i = 0; i < num_points; i++) + { + object->coords[i] = convertOcdPoint(ocd_points[i]); + setPointFlags(object, i, is_area, ocd_points[i]); + } + + // For path objects, create closed parts where the position of the last point is equal to that of the first point + if (object->getType() == Object::Path) + { + int start = 0; + for (int i = 0; i < (int)object->coords.size(); ++i) + { + if (!object->coords[i].isHolePoint() && i < (int)object->coords.size() - 1) + continue; + + if (object->coords[i].isPositionEqualTo(object->coords[start])) + { + MapCoord coord = object->coords[start]; + coord.setCurveStart(false); + coord.setHolePoint(true); + coord.setClosePoint(true); + object->coords[i] = coord; + } + + start = i + 1; + } + } +} + +/** Translates an OCAD text object path into a Mapper text object specifier, if possible. + * If successful, sets either 1 or 2 coordinates in the text object and returns true. + * If the OCAD path was not importable, leaves the TextObject alone and returns false. + */ +bool OcdFileImport::fillTextPathCoords(TextObject *object, TextSymbol *symbol, quint16 npts, const Ocd::OcdPoint32 *ocd_points) +{ + // text objects either have 1 point (free anchor) or 2 (midpoint/size) + // OCAD appears to always have 5 or 4 points (possible single anchor, then 4 corner coordinates going clockwise from anchor). + if (npts == 0) return false; + + if (npts == 4) + { + // Box text + MapCoord bottom_left = convertOcdPoint(ocd_points[0]); + MapCoord top_right = convertOcdPoint(ocd_points[2]); + MapCoord top_left = convertOcdPoint(ocd_points[3]); + + // According to Purple Pen source code: OC*D adds an extra internal leading (incorrectly). + QFontMetricsF metrics = symbol->getFontMetrics(); + double top_adjust = -symbol->getFontSize() + (metrics.ascent() + metrics.descent() + 0.5) / symbol->calculateInternalScaling(); + + MapCoordF adjust_vector = MapCoordF(top_adjust * sin(object->getRotation()), top_adjust * cos(object->getRotation())); + top_left = MapCoord(top_left.x() + adjust_vector.x(), top_left.y() + adjust_vector.y()); + top_right = MapCoord(top_right.x() + adjust_vector.x(), top_right.y() + adjust_vector.y()); + + object->setBox((bottom_left.nativeX() + top_right.nativeX()) / 2, (bottom_left.nativeY() + top_right.nativeY()) / 2, + top_left.distanceTo(top_right), top_left.distanceTo(bottom_left)); + object->setVerticalAlignment(TextObject::AlignTop); + } + else + { + // Single anchor text + if (npts != 5) + addWarning(tr("Trying to import a text object with unknown coordinate format")); + + // anchor point + MapCoord coord = convertOcdPoint(ocd_points[0]); + object->setAnchorPosition(coord.nativeX(), coord.nativeY()); + object->setVerticalAlignment(text_valign_map.value(symbol)); + } + + return true; +} + +void OcdFileImport::setBasicAttributes(OcdFileImport::OcdImportedTextSymbol* symbol, const QString& font_name, const Ocd::BasicTextAttributesV8& attributes) +{ + symbol->font_family = font_name; + symbol->color = convertColor(attributes.color); + symbol->font_size = qRound(100.0 * attributes.font_size / 72.0 * 25.4); + symbol->bold = (attributes.font_weight>= 550) ? true : false; + symbol->italic = (attributes.font_italic) ? true : false; + symbol->underline = false; + symbol->kerning = false; + symbol->line_below = false; + symbol->custom_tabs.resize(0); + + if (attributes.font_weight != 400 && attributes.font_weight != 700) + { + addSymbolWarning(symbol, tr("Ignoring custom weight (%1).").arg(attributes.font_weight)); + } + + switch (attributes.alignment & Ocd::HAlignMask) + { + case Ocd::HAlignLeft: + text_halign_map[symbol] = TextObject::AlignLeft; + break; + case Ocd::HAlignRight: + text_halign_map[symbol] = TextObject::AlignRight; + break; + case Ocd::HAlignJustified: + /// \todo Implement justified alignment + addSymbolWarning(symbol, tr("Justified alignment is not supported.")); + // fall through + default: + text_halign_map[symbol] = TextObject::AlignHCenter; + } + + switch (attributes.alignment & Ocd::VAlignMask) + { + case Ocd::VAlignTop: + text_valign_map[symbol] = TextObject::AlignTop; + break; + case Ocd::VAlignMiddle: + text_valign_map[symbol] = TextObject::AlignVCenter; + break; + default: + addSymbolWarning(symbol, tr("Vertical alignment '%1' is not supported.").arg(attributes.alignment & Ocd::VAlignMask)); + // fall through + case Ocd::VAlignBottom: + text_valign_map[symbol] = TextObject::AlignBaseline; + } + + if (attributes.char_spacing != 0) + { + symbol->character_spacing = attributes.char_spacing / 100.0; + addSymbolWarning(symbol, tr("Custom character spacing may be incorrect.")); + } + + if (attributes.word_spacing != 100) + { + addSymbolWarning(symbol, tr("Ignoring custom word spacing (%1 %).").arg(attributes.word_spacing)); + } + + symbol->updateQFont(); +} + +void OcdFileImport::setSpecialAttributes(OcdFileImport::OcdImportedTextSymbol* symbol, const Ocd::SpecialTextAttributesV8& attributes) +{ + // Convert line spacing + double absolute_line_spacing = 0.00001 * symbol->font_size * attributes.line_spacing; + symbol->line_spacing = absolute_line_spacing / (symbol->getFontMetrics().lineSpacing() / symbol->calculateInternalScaling()); + symbol->paragraph_spacing = convertLength(attributes.para_spacing); + + symbol->line_below = attributes.line_below_on; + symbol->line_below_color = convertColor(attributes.line_below_color); + symbol->line_below_width = convertLength(attributes.line_below_width); + symbol->line_below_distance = convertLength(attributes.line_below_offset); + + symbol->custom_tabs.resize(attributes.num_tabs); + for (int i = 0; i < attributes.num_tabs; ++i) + symbol->custom_tabs[i] = convertLength(attributes.tab_pos[i]); + + if (attributes.indent_first_line != 0 || attributes.indent_other_lines != 0) + { + addSymbolWarning(symbol, tr("Ignoring custom indents (%1/%2).").arg(attributes.indent_first_line).arg(attributes.indent_other_lines)); + } +} + +void OcdFileImport::setFraming(OcdFileImport::OcdImportedTextSymbol* symbol, const Ocd::FramingAttributesV8& framing) +{ + switch (framing.mode) + { + case Ocd::FramingShadow: + symbol->framing = true; + symbol->framing_mode = TextSymbol::ShadowFraming; + symbol->framing_color = convertColor(framing.color); + symbol->framing_shadow_x_offset = convertLength(framing.offset_x); + symbol->framing_shadow_y_offset = -1 * convertLength(framing.offset_y); + break; + case Ocd::FramingLine: // since V7 + symbol->framing = true; + symbol->framing_mode = TextSymbol::LineFraming; + symbol->framing_line_half_width = convertLength(framing.line_width); + break; + case Ocd::FramingRectangle: + default: + addSymbolWarning(symbol, tr("Ignoring text framing (mode %1).").arg(framing.mode)); + // fall through + case Ocd::FramingNone: + symbol->framing = false; + } +} + +void OcdFileImport::import(bool load_symbols_only) +{ + Q_ASSERT(buffer.isEmpty()); + + buffer.clear(); + buffer.append(stream->readAll()); + if (buffer.isEmpty()) + throw FileFormatException(Importer::tr("Could not read file: %1").arg(stream->errorString())); + + if (buffer.size() < (int)sizeof(Ocd::FormatGeneric::FileHeader)) + throw FileFormatException(Importer::tr("Could not read file: %1").arg(tr("Invalid data."))); + + OcdFile< Ocd::FormatGeneric > generic_file(buffer); + if (generic_file.header()->vendor_mark != 0x0cad) // This also tests correct endianess... + throw FileFormatException(Importer::tr("Could not read file: %1").arg(tr("Invalid data."))); + + int version = generic_file.header()->version; + switch (version) + { + case 6: + case 7: + case 8: + // Note: Version 6 and 7 do have some differences, which will need to be + // handled in the version 8 implementation by looking up the + // actual format version in the file header. + if (Settings::getInstance().getSetting(Settings::General_NewOcd8Implementation).toBool()) + importImplementation< Ocd::FormatV8 >(load_symbols_only); + else + importImplementationLegacy(load_symbols_only); + break; + case 9: + importImplementation< Ocd::FormatV9 >(load_symbols_only); + break; + case 10: + importImplementation< Ocd::FormatV10 >(load_symbols_only); + break; + case 11: + importImplementation< Ocd::FormatV11 >(load_symbols_only); + break; + case 12: + importImplementation< Ocd::FormatV12 >(load_symbols_only); + break; + default: + throw FileFormatException( + Importer::tr("Could not read file: %1"). + arg(tr("OCD files of version %1 are not supported!").arg(version)) + ); + } +} + +void OcdFileImport::finishImport() +{ + if (delegate) + { + // The current warnings and actions are already propagated. + std::size_t warnings_size = delegate->warnings().size(); + std::size_t actions_size = delegate->actions().size(); + + delegate->finishImport(); + + // Propagate new warnings and actions from the delegate to this importer. + std::for_each(begin(delegate->warnings()) + warnings_size, end(delegate->warnings()), [this](const QString& w) { addWarning(w); }); + std::for_each(begin(delegate->actions()) + actions_size, end(delegate->actions()), [this](const ImportAction& a) { addAction(a); }); + } +} diff --git a/src/fileformats/ocd_file_format_p.h b/src/fileformats/ocd_file_import.h similarity index 70% rename from src/fileformats/ocd_file_format_p.h rename to src/fileformats/ocd_file_import.h index 67be5727c..74d0d2f8f 100644 --- a/src/fileformats/ocd_file_format_p.h +++ b/src/fileformats/ocd_file_import.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 Kai Pastor + * Copyright 2013-2016 Kai Pastor * * Some parts taken from file_format_oc*d8{.h,_p.h,cpp} which are * Copyright 2012 Pete Curtis @@ -20,16 +20,18 @@ * along with OpenOrienteering. If not, see . */ -#ifndef _OPENORIENTEERING_OCD_FILE_FORMAT_P_ -#define _OPENORIENTEERING_OCD_FILE_FORMAT_P_ +#ifndef OPENORIENTEERING_OCD_FILE_IMPORT +#define OPENORIENTEERING_OCD_FILE_IMPORT -#include -#include +#include "../file_import_export.h" #include +#include +#include + #include "ocd_types.h" -#include "../file_import_export.h" +#include "ocd_types_v8.h" #include "../object.h" #include "../object_text.h" #include "../symbol.h" @@ -95,12 +97,13 @@ Q_OBJECT friend class OcdFileImport; public: - OcdImportedPathObject(Symbol* symbol = NULL) : PathObject(symbol) { } + OcdImportedPathObject(Symbol* symbol = nullptr) : PathObject(symbol) { } }; public: OcdFileImport(QIODevice* stream, Map *map, MapView *view); - virtual ~OcdFileImport(); + + virtual ~OcdFileImport() override; void setCustom8BitEncoding(const char *encoding); @@ -127,64 +130,110 @@ Q_OBJECT MapColor* convertColor(int ocd_color); - void addSymbolWarning(LineSymbol* symbol, const QString& warning); + void addSymbolWarning(const LineSymbol* symbol, const QString& warning); - void addSymbolWarning(TextSymbol* symbol, const QString& warning); + void addSymbolWarning(const TextSymbol* symbol, const QString& warning); - virtual void finishImport(); + virtual void finishImport() override; protected: - virtual void import(bool load_symbols_only); + virtual void import(bool load_symbols_only) override; + + void importImplementationLegacy(bool load_symbols_only); template< class F > void importImplementation(bool load_symbols_only); + + void importGeoreferencing(const OcdFile& file); + template< class F > void importGeoreferencing(const OcdFile< F >& file); /// Imports string 1039. - void importScalesSettings(const QString& param_string); + void importGeoreferencing(const QString& param_string); + + /// Imports string 1039 field i. + void applyGridAndZone(Georeferencing& georef, const QString& combined_grid_zone); + + + void importColors(const OcdFile& file); template< class F > void importColors(const OcdFile< F >& file); MapColor* importColor(const QString& param_string); + template< class F > void importSymbols(const OcdFile< F >& file); + + void importObjects(const OcdFile& file); + template< class F > void importObjects(const OcdFile< F >& file); + template< class F > void importTemplates(const OcdFile< F >& file); Template* importTemplate(const QString& param_string, const int ocd_version); + + void importExtras(const OcdFile& file); + template< class F > void importExtras(const OcdFile< F >& file); + + void importView(const OcdFile& file); + template< class F > void importView(const OcdFile< F >& file); void importView(const QString& param_string); + // Symbol import template< class S > - PointSymbol* importPointSymbol(const S& ocd_symbol); + PointSymbol* importPointSymbol(const S& ocd_symbol, int ocd_version); template< class S > - Symbol* importLineSymbol(const S& ocd_symbol); + Symbol* importLineSymbol(const S& ocd_symbol, int ocd_version); + + OcdImportedLineSymbol* importLineSymbolBase(const Ocd::LineSymbolCommonV8& attributes); + + OcdImportedLineSymbol* importLineSymbolFraming(const Ocd::LineSymbolCommonV8& attributes, const LineSymbol* main_line); + + OcdImportedLineSymbol* importLineSymbolDoubleBorder(const Ocd::LineSymbolCommonV8& attributes); + + void setupLineSymbolForBorder(OcdImportedLineSymbol* line_for_borders, const Ocd::LineSymbolCommonV8& attributes); + + void setupLineSymbolPointSymbol(OcdImportedLineSymbol* line_symbol, const Ocd::LineSymbolCommonV8& attributes, const Ocd::PointSymbolElementV8* elements, int ocd_version); + + void mergeLineSymbol(CombinedSymbol* full_line, LineSymbol* main_line, LineSymbol* framing_line, LineSymbol* double_line); + + AreaSymbol* importAreaSymbol(const Ocd::AreaSymbolV8& ocd_symbol, int ocd_version); template< class S > AreaSymbol* importAreaSymbol(const S& ocd_symbol, int ocd_version); + void setupAreaSymbolCommon( + OcdImportedAreaSymbol* symbol, + bool fill_on, + const Ocd::AreaSymbolCommonV8& ocd_symbol, + std::size_t data_size, + const Ocd::PointSymbolElementV8* elements, + int ocd_version + ); + template< class S > - TextSymbol* importTextSymbol(const S& ocd_symbol); + TextSymbol* importTextSymbol(const S& ocd_symbol, int ocd_version); template< class S > - TextSymbol* importLineTextSymbol(const S& ocd_symbol); + TextSymbol* importLineTextSymbol(const S& ocd_symbol, int ocd_version); template< class S > LineSymbol* importRectangleSymbol(const S& ocd_symbol); @@ -192,23 +241,24 @@ Q_OBJECT template< class S > void setupBaseSymbol(Symbol* symbol, const S& ocd_symbol); - template< class E > - void setupPointSymbolPattern(PointSymbol* symbol, std::size_t data_size, const E* elements); + void setupPointSymbolPattern(PointSymbol* symbol, std::size_t data_size, const Ocd::PointSymbolElementV8* elements, int version); - template< class E > - int circleRadius(const E* element) const; // Object import template< class O > - Object* importObject(const O& ocd_object, MapPart* part); + Object* importObject(const O& ocd_object, MapPart* part, int ocd_version); + + QString getObjectText(const Ocd::ObjectV8& ocd_object, int ocd_version) const; template< class O > - QString getObjectText(const O& ocd_object) const; + QString getObjectText(const O& ocd_object, int ocd_version) const; template< class O > Object* importRectangleObject(const O& ocd_object, MapPart* part, const OcdFileImport::RectangleInfo& rect); + Object* importRectangleObject(const Ocd::OcdPoint32* ocd_points, MapPart* part, const OcdFileImport::RectangleInfo& rect); + // Some helper functions that are used in multiple places void setPointFlags(OcdImportedPathObject* object, quint16 pos, bool is_area, const Ocd::OcdPoint32& ocd_point); @@ -219,6 +269,12 @@ Q_OBJECT bool fillTextPathCoords(TextObject* object, TextSymbol* symbol, quint16 npts, const Ocd::OcdPoint32* ocd_points); + void setBasicAttributes(OcdImportedTextSymbol* symbol, const QString& font_name, const Ocd::BasicTextAttributesV8& attributes); + + void setSpecialAttributes(OcdImportedTextSymbol* symbol, const Ocd::SpecialTextAttributesV8& attributes); + + void setFraming(OcdImportedTextSymbol* symbol, const Ocd::FramingAttributesV8& framing); + protected: /// The locale is used for number formatting. QLocale locale; @@ -251,14 +307,12 @@ Q_OBJECT // ### OcdFileImport inline code ### template< std::size_t N > -inline QString OcdFileImport::convertOcdString(const Ocd::PascalString& src) const { return custom_8bit_encoding->toUnicode(src.data, src.length); } template< std::size_t N > -inline QString OcdFileImport::convertOcdString(const Ocd::Utf8PascalString& src) const { return QString::fromUtf8(src.data, src.length); @@ -281,7 +335,6 @@ QString OcdFileImport::convertOcdString< Ocd::Utf8Encoding >(const char* src, st } template< class E > -inline QString OcdFileImport::convertOcdString(const QByteArray& data) const { return OcdFileImport::convertOcdString< E >(data.constData(), data.length()); @@ -323,11 +376,11 @@ MapColor *OcdFileImport::convertColor(int ocd_color) if (!color_index.contains(ocd_color)) { addWarning(tr("Color id not found: %1, ignoring this color").arg(ocd_color)); - return NULL; + return nullptr; } return color_index[ocd_color]; } -#endif // _OPENORIENTEERING_OCD_FILE_FORMAT_P_ +#endif // OPENORIENTEERING_OCD_FILE_IMPORT diff --git a/src/fileformats/ocd_types.cpp b/src/fileformats/ocd_types.cpp index da30136fd..0780c0d44 100644 --- a/src/fileformats/ocd_types.cpp +++ b/src/fileformats/ocd_types.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013 Kai Pastor + * Copyright 2013, 2016 Kai Pastor * * This file is part of OpenOrienteering. * @@ -22,6 +22,7 @@ #include "ocd_types_v9.h" #include "ocd_types_v10.h" #include "ocd_types_v11.h" +#include "ocd_types_v12.h" namespace Ocd { @@ -40,4 +41,6 @@ namespace Ocd Q_STATIC_ASSERT(sizeof(FileHeaderV10) == 48); Q_STATIC_ASSERT(sizeof(FileHeaderV11) == 48); + + Q_STATIC_ASSERT(sizeof(FileHeaderV12) == 60); } diff --git a/src/fileformats/ocd_types.h b/src/fileformats/ocd_types.h index 4aa608996..3834141fb 100644 --- a/src/fileformats/ocd_types.h +++ b/src/fileformats/ocd_types.h @@ -1,5 +1,5 @@ /* - * Copyright 2013, 2015 Kai Pastor + * Copyright 2013, 2015, 2016 Kai Pastor * * This file is part of OpenOrienteering. * @@ -17,11 +17,10 @@ * along with OpenOrienteering. If not, see . */ -#ifndef _OPENORIENTEERING_OCD_TYPES_ -#define _OPENORIENTEERING_OCD_TYPES_ +#ifndef OPENORIENTEERING_OCD_TYPES_H +#define OPENORIENTEERING_OCD_TYPES_H #include -#include #include #include @@ -92,13 +91,23 @@ namespace Ocd /** * The generic header at the beginning of all supported OCD file formats. + * + * For implementation efficiency, this header is generalized in comparison + * to the upstream documentation: + * + * - Until V8, the format actually used a 16 bit file type field called + * "section mark", but no file status field. + * - Until V9, the format actually used a 16 bit subversion field, but no + * subsubversion field. */ struct FileHeaderGeneric { quint16 vendor_mark; - quint16 RESERVED_MEMBER; + quint8 file_type; /// aka "section mark" until V8 + quint8 file_status_V9; /// \since V9 quint16 version; - quint16 subversion; + quint8 subversion; + quint8 subsubversion_V10; /// \since V10 }; /** @@ -121,7 +130,7 @@ namespace Ocd { quint32 pos; quint32 size; - qint32 type; + qint32 type; quint32 obj_index; }; @@ -167,6 +176,88 @@ namespace Ocd #pragma pack(pop) + /** + * Symbol type values. + */ + enum SymbolType + { + SymbolTypePoint = 1, + SymbolTypeLine = 2, + SymbolTypeArea = 3, + SymbolTypeText = 4, + SymbolTypeRectangle_V8 = 5, /// Until V8 + SymbolTypeLineText = 6, /// \since V9 + SymbolTypeRectangle_V9 = 7 /// \since V9 + }; + + /** + * Status flags for symbols. + */ + enum SymbolStatus + { + SymbolNormal = 0, + SymbolProtected = 1, + SymbolHidden = 2 + }; + + /** + * Status values for objects. + */ + enum ObjectStatus + { + ObjectDeleted = 0, + ObjectNormal = 1, + ObjectHidden = 2, + ObjectDeletedForUndo = 3 + }; + + /** + * Text alignment flags. + */ + enum TextAlignment + { + HAlignMask = 0x03, + HAlignLeft = 0x00, + HAlignCenter = 0x01, + HAlignRight = 0x02, + HAlignJustified = 0x03, /// All-line for line text symbols + VAlignMask = 0x0c, /// \since V10 + VAlignBottom = 0x00, /// \since V10 + VAlignMiddle = 0x04, /// \since V10 + VAlignTop = 0x08 /// \since V10 + }; + + /** + * Area hatch mode values. + */ + enum HatchMode + { + HatchNone = 0, + HatchSingle = 1, + HatchCross = 2 + }; + + /** + * Area pattern structure values. + */ + enum StructureMode + { + StructureNone = 0, + StructureAlignedRows = 1, + StructureShiftedRows = 2 + }; + + /** + * + */ + enum FramingMode + { + FramingNone = 0, + FramingShadow = 1, /// Somehow different in older versions + FramingLine = 2, /// \since V7 + FramingRectangle = 3 /// \since V8; Not for line text symbols + }; + /** * A generic OCD file format trait. * @@ -183,15 +274,6 @@ namespace Ocd struct Object { typedef quint32 IndexEntryType; }; }; - /** - * A OCD file format trait for selecting the old version 8 importer. - */ - struct FormatLegacyImporter - { - static constexpr int version() { return 8; } - - typedef FileHeaderGeneric FileHeader; - }; } @@ -497,7 +579,7 @@ quint32 FirstIndexBlock::operator()(const OcdFile* file) const template< class F > quint32 FirstIndexBlock::operator()(const OcdFile* file) const { - return file->header()->first_string_block; + return (file->header()->version < 8) ? 0 : file->header()->first_string_block; } template< class F > @@ -542,15 +624,21 @@ const OcdEntityIndexIterator& OcdEntityIndexIterator::operator++() { index = 0; quint32 next_block = block->next_block; - if (next_block) + if (next_block == 0) { - block = reinterpret_cast(&(*data)[next_block]); + block = nullptr; + data = nullptr; } - else + else if (Q_UNLIKELY(next_block >= (unsigned int)data->byteArray().size())) { + qWarning("OcdEntityIndexIterator: Next index block is out of bounds"); block = nullptr; data = nullptr; } + else + { + block = reinterpret_cast(&(*data)[next_block]); + } } } while (block && !block->entries[index].pos); @@ -770,4 +858,4 @@ const typename F::Object& OcdFile::operator[](const typename OcdFile::Obje return reinterpret_cast((*this)[object_entry.pos]); } -#endif +#endif // OPENORIENTEERING_OCD_TYPES_H diff --git a/src/fileformats/ocd_types_v10.h b/src/fileformats/ocd_types_v10.h index 69e2fd533..347c8f32e 100644 --- a/src/fileformats/ocd_types_v10.h +++ b/src/fileformats/ocd_types_v10.h @@ -1,5 +1,5 @@ /* - * Copyright 2013, 2015 Kai Pastor + * Copyright 2013, 2015, 2016 Kai Pastor * * This file is part of OpenOrienteering. * @@ -17,8 +17,8 @@ * along with OpenOrienteering. If not, see . */ -#ifndef _OPENORIENTEERING_OCD_TYPES_V10_ -#define _OPENORIENTEERING_OCD_TYPES_V10_ +#ifndef OPENORIENTEERING_OCD_TYPES_V10 +#define OPENORIENTEERING_OCD_TYPES_V10 #include "ocd_types.h" #include "ocd_types_v9.h" @@ -28,156 +28,27 @@ namespace Ocd #pragma pack(push, 1) - struct FileHeaderV10 - { - quint16 vendor_mark; - quint8 file_type; - quint8 file_status; - quint16 version; - quint8 subversion; - quint8 subsubversion; - quint32 first_symbol_block; - quint32 first_object_block; - quint32 RESERVED_MEMBER[4]; - quint32 first_string_block; - quint32 file_name_pos; - quint32 file_name_size; - quint32 RESERVED_MEMBER; - }; + using FileHeaderV10 = FileHeaderV9; - typedef BaseSymbolV9 BaseSymbolV10; + using BaseSymbolV10 = BaseSymbolV9; - typedef PointSymbolElementV9 PointSymbolElementV10; + using PointSymbolElementV10 = PointSymbolElementV9; - typedef PointSymbolV9 PointSymbolV10; + using PointSymbolV10 = PointSymbolV9; - typedef LineSymbolV9 LineSymbolV10; + using LineSymbolV10 = LineSymbolV9; - typedef AreaSymbolV9 AreaSymbolV10; + using AreaSymbolV10 = AreaSymbolV9; - struct TextSymbolV10 - { - typedef BaseSymbolV10 BaseSymbol; - - BaseSymbol base; - - PascalString<31> font_name; - quint16 font_color; - quint16 font_size; - quint16 font_weight; - quint8 font_italic; - quint8 RESERVED_MEMBER; - quint16 char_spacing; - quint16 word_spacing; - quint16 alignment; // TODO: changed from OCD9 - quint16 line_spacing; - qint16 para_spacing; - quint16 indent_first_line; - quint16 indent_other_lines; - quint16 num_tabs; - quint32 tab_pos[32]; - quint16 line_below_on; - quint16 line_below_color; - quint16 line_below_width; - quint16 line_below_offset; - quint16 RESERVED_MEMBER; - quint8 framing_mode; - quint8 framing_line_style; - quint8 point_symbol_on; - quint32 point_symbol_number; - QChar RESERVED_MEMBER[18]; - quint16 framing_border_left; - quint16 framing_border_bottom; - quint16 framing_border_right; - quint16 framing_border_top; - quint16 framing_color; - quint16 framing_line_width; - quint16 RESERVED_MEMBER[2]; - quint16 framing_offset_x; - quint16 framing_offset_y; - - enum TextAlignment - { - HAlignMask = 0x03, - HAlignLeft = 0x00, - HAlignCenter = 0x01, - HAlignRight = 0x02, - HAlignJustified = 0x03, - VAlignMask = 0x0c, - VAlignBottom = 0x00, - VAlignMiddle = 0x04, - VAlignTop = 0x08 - }; - }; + using TextSymbolV10 = TextSymbolV9; - struct LineTextSymbolV10 // TODO: use and test... - { - typedef BaseSymbolV10 BaseSymbol; - - BaseSymbol base; - - PascalString<31> font_name; - quint16 font_color; - quint16 font_size; - quint16 font_weight; - quint8 font_italic; - quint8 RESERVED_MEMBER; - quint16 char_spacing; - quint16 word_spacing; - quint16 alignment; - quint8 framing_mode; - quint8 framing_line_style; - char RESERVED_MEMBER[32]; - quint16 framing_color; - quint16 framing_line_width; - quint16 RESERVED_MEMBER[2]; - quint16 framing_offset_x; - quint16 framing_offset_y; - }; + using LineTextSymbolV10 = LineTextSymbolV9; - struct RectangleSymbolV10 - { - typedef BaseSymbolV10 BaseSymbol; - - BaseSymbol base; - - quint16 line_color; - quint16 line_width; - quint16 corner_radius; - quint16 grid_flags; - quint16 cell_width; - quint16 cell_height; - quint16 RESERVED_MEMBER[2]; - quint16 unnumbered_cells; - PascalString<3> unnumbered_text; - quint16 RESERVED_MEMBER; - char RESERVED_MEMBER[32]; - quint16 RESERVED_MEMBER; - quint16 font_size; - quint16 RESERVED_MEMBER[4]; - }; + using RectangleSymbolV10 = RectangleSymbolV9; - typedef ObjectIndexEntryV9 ObjectIndexEntryV10; + using ObjectIndexEntryV10 = ObjectIndexEntryV9; - struct ObjectV10 - { - typedef ObjectIndexEntryV10 IndexEntryType; - - qint32 symbol; - quint8 type; - quint8 RESERVED_MEMBER; - qint16 angle; - quint32 num_items; - quint16 num_text; - quint16 RESERVED_MEMBER; - quint32 color; - quint16 line_width; - quint16 diam_flags; - quint32 RESERVED_MEMBER[3]; - quint32 height_mm; - - OcdPoint32 coords[1]; - }; + using ObjectV10 = ObjectV9; #pragma pack(pop) @@ -199,17 +70,7 @@ namespace Ocd typedef ObjectV10 Object; typedef Custom8BitEncoding Encoding; - - enum SymbolType - { - TypePoint = 1, - TypeLine = 2, - TypeArea = 3, - TypeText = 4, - TypeLineText = 6, - TypeRectangle = 7 - }; }; } -#endif // _OPENORIENTEERING_OCD_TYPES_V10_ +#endif // OPENORIENTEERING_OCD_TYPES_V10_H diff --git a/src/fileformats/ocd_types_v11.h b/src/fileformats/ocd_types_v11.h index 584abfe9d..44b02d3c7 100644 --- a/src/fileformats/ocd_types_v11.h +++ b/src/fileformats/ocd_types_v11.h @@ -1,5 +1,5 @@ /* - * Copyright 2013, 2015 Kai Pastor + * Copyright 2013, 2015, 2016 Kai Pastor * * This file is part of OpenOrienteering. * @@ -17,8 +17,8 @@ * along with OpenOrienteering. If not, see . */ -#ifndef _OPENORIENTEERING_OCD_TYPES_V11_ -#define _OPENORIENTEERING_OCD_TYPES_V11_ +#ifndef OPENORIENTEERING_OCD_TYPES_V11_H +#define OPENORIENTEERING_OCD_TYPES_V11_H #include "ocd_types.h" #include "ocd_types_v10.h" @@ -28,23 +28,7 @@ namespace Ocd #pragma pack(push, 1) - struct FileHeaderV11 - { - quint16 vendor_mark; - quint8 file_type; - quint8 file_status; - quint16 version; - quint8 subversion; - quint8 subsubversion; - quint32 first_symbol_block; - quint32 first_object_block; - quint32 offline_sync_serial; - quint32 RESERVED_MEMBER[3]; - quint32 first_string_block; - quint32 file_name_pos; - quint32 file_name_size; - quint32 RESERVED_MEMBER; - }; + using FileHeaderV11 = FileHeaderV10; struct BaseSymbolV11 { @@ -64,22 +48,16 @@ namespace Ocd quint8 cs_type; quint8 cd_flags; qint32 extent; - qint32 file_pos; + quint32 file_pos; quint8 RESERVED_MEMBER[2]; quint16 num_colors; quint16 colors[14]; QChar description[64]; quint8 icon_bits[484]; quint16 group[64]; - - enum StatusFlag - { - StatusProtected = 1, - StatusHidden = 2 - }; }; - typedef PointSymbolElementV10 PointSymbolElementV11; + using PointSymbolElementV11 = PointSymbolElementV10; struct PointSymbolV11 { @@ -100,62 +78,9 @@ namespace Ocd BaseSymbol base; - quint16 line_color; - quint16 line_width; - quint16 line_style; - qint16 dist_from_start; - qint16 dist_from_end; - qint16 main_length; - qint16 end_length; - qint16 main_gap; - qint16 sec_gap; - qint16 end_gap; - qint16 min_sym; - qint16 num_prim_sym; - qint16 prim_sym_dist; - quint16 double_mode; - quint16 double_flags; - quint16 double_color; - quint16 double_left_color; - quint16 double_right_color; - qint16 double_width; - qint16 double_left_width; - qint16 double_right_width; - qint16 double_length; - qint16 double_gap; - quint16 double_background_color; - quint16 RESERVED_MEMBER[2]; - quint16 dec_mode; - quint16 dec_last; - quint16 RESERVED_MEMBER; - quint16 framing_color; - qint16 framing_width; - quint16 framing_style; - quint16 primary_data_size; - quint16 secondary_data_size; - quint16 corner_data_size; - quint16 start_data_size; - quint16 end_data_size; - quint8 active_symbols; - quint8 RESERVED_MEMBER; + LineSymbolCommonV8 common; Element begin_of_elements[1]; - - enum LineStyleFlag - { - BevelJoin_FlatCap = 0, - RoundJoin_RoundCap = 1, - BevelJoin_PointedCap = 2, - RoundJoin_PointedCap = 3, - MiterJoin_FlatCap = 4, - MiterJoin_PointedCap = 6 - }; - - enum DoubleLineFlag - { - DoubleFillColorOn = 1, - DoubleBackgroundColorOn = 2 - }; }; struct AreaSymbolV11 @@ -166,37 +91,11 @@ namespace Ocd BaseSymbol base; quint32 border_symbol; - quint16 fill_color; - quint16 hatch_mode; - quint16 hatch_color; - quint16 hatch_line_width; - quint16 hatch_dist; - qint16 hatch_angle_1; - qint16 hatch_angle_2; - quint8 fill_on; - quint8 border_on; - quint16 structure_mode; - quint16 structure_width; - quint16 structure_height; - qint16 structure_angle; + AreaSymbolCommonV8 common; quint16 RESERVED_MEMBER; quint16 data_size; Element begin_of_elements[1]; - - enum HatchMode - { - HatchNone = 0, - HatchSingle = 1, - HatchCross = 2 - }; - - enum StructureMode - { - StructureNone = 0, - StructureAlignedRows = 1, - StructureShiftedRows = 2 - }; }; struct TextSymbolV11 @@ -205,65 +104,22 @@ namespace Ocd BaseSymbol base; - Utf8PascalString<31> font_name; - quint16 font_color; - quint16 font_size; - quint16 font_weight; - quint8 font_italic; - quint8 RESERVED_MEMBER; - quint16 char_spacing; - quint16 word_spacing; - quint16 alignment; - quint16 line_spacing; - qint16 para_spacing; - quint16 indent_first_line; - quint16 indent_other_lines; - quint16 num_tabs; - quint32 tab_pos[32]; - quint16 line_below_on; - quint16 line_below_color; - quint16 line_below_width; - quint16 line_below_offset; - quint16 RESERVED_MEMBER; - quint8 framing_mode; - quint8 framing_line_style; - quint8 point_symbol_on; - quint32 point_symbol_number; - QChar RESERVED_MEMBER[18]; - quint16 framing_border_left; - quint16 framing_border_bottom; - quint16 framing_border_right; - quint16 framing_border_top; - quint16 framing_color; - quint16 framing_line_width; - quint16 RESERVED_MEMBER[2]; - quint16 framing_offset_x; - quint16 framing_offset_y; + Utf8PascalString<31> font_name; + BasicTextAttributesV8 basic; + SpecialTextAttributesV8 special; + quint16 RESERVED_MEMBER; + FramingAttributesV8 framing; }; - struct LineTextSymbolV11 // TODO: use and test... + struct LineTextSymbolV11 { typedef BaseSymbolV11 BaseSymbol; BaseSymbol base; - Utf8PascalString<31> font_name; - quint16 font_color; - quint16 font_size; - quint16 font_weight; - quint8 font_italic; - quint8 RESERVED_MEMBER; - quint16 char_spacing; - quint16 word_spacing; - quint16 alignment; - quint8 framing_mode; - quint8 framing_line_style; - QChar RESERVED_MEMBER[32]; - quint16 framing_color; - quint16 framing_line_width; - quint16 RESERVED_MEMBER[2]; - quint16 framing_offset_x; - quint16 framing_offset_y; + Utf8PascalString<31> font_name; + BasicTextAttributesV8 basic; + FramingAttributesV8 framing; }; struct RectangleSymbolV11 @@ -280,61 +136,17 @@ namespace Ocd quint16 cell_height; quint16 RESERVED_MEMBER[2]; quint16 unnumbered_cells; - QChar unnumbered_text[4]; + Utf8PascalString<3> unnumbered_text; quint16 line_style; - QChar RESERVED_MEMBER[32]; + Utf8PascalString<31> RESERVED_MEMBER; quint16 RESERVED_MEMBER; - quint16 font_size; + quint16 font_size_V10; /// \since V10 quint16 RESERVED_MEMBER[4]; }; - struct ObjectIndexEntryV11 - { - OcdPoint32 bottom_left_bound; - OcdPoint32 top_right_bound; - quint32 pos; - quint32 size; - qint32 symbol; - quint8 type; - quint8 encryption_mode; - quint8 status; - quint8 view_type; - quint16 color; - quint16 group; - quint16 layer; - quint8 layout_font; - quint8 RESERVED_MEMBER; - - enum ObjectStatus - { - StatusDeleted = 0, - StatusNormal = 1, - StatusHidden = 2, - StatusDeletedForUndo = 3 - }; - }; + using ObjectIndexEntryV11 = ObjectIndexEntryV10; - struct ObjectV11 - { - typedef ObjectIndexEntryV11 IndexEntryType; - - qint32 symbol; - quint8 type; - quint8 customer; - qint16 angle; - quint32 num_items; - quint16 num_text; - quint8 mark; - quint8 snapping_mark; - qint32 color; - quint16 line_width; - quint16 diam_flags; - quint32 server_object_id; - quint32 height; - quint64 date; - - OcdPoint32 coords[1]; - }; + using ObjectV11 = ObjectV10; #pragma pack(pop) @@ -356,17 +168,7 @@ namespace Ocd typedef ObjectV11 Object; typedef Utf8Encoding Encoding; - - enum SymbolType - { - TypePoint = 1, - TypeLine = 2, - TypeArea = 3, - TypeText = 4, - TypeLineText = 6, - TypeRectangle = 7 - }; }; } -#endif // _OPENORIENTEERING_OCD_TYPES_V11_ +#endif // OPENORIENTEERING_OCD_TYPES_V11_H diff --git a/src/fileformats/ocd_types_v12.h b/src/fileformats/ocd_types_v12.h new file mode 100644 index 000000000..0ca78d80c --- /dev/null +++ b/src/fileformats/ocd_types_v12.h @@ -0,0 +1,120 @@ +/* + * Copyright 2013, 2015, 2016 Kai Pastor + * + * This file is part of OpenOrienteering. + * + * OpenOrienteering 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. + * + * OpenOrienteering 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 OpenOrienteering. If not, see . + */ + +#ifndef OPENORIENTEERING_OCD_TYPES_V12_H +#define OPENORIENTEERING_OCD_TYPES_V12_H + +#include "ocd_types.h" +#include "ocd_types_v11.h" + +namespace Ocd +{ + +#pragma pack(push, 1) + + struct FileHeaderV12 : public FileHeaderV11 + { + quint32 RESERVED_MEMBER[2]; + quint32 first_multi_rep_block; + }; + + using BaseSymbolV12 = BaseSymbolV11; + + using PointSymbolElementV12 = PointSymbolElementV11; + + using PointSymbolV12 = PointSymbolV11; + + using LineSymbolV12 = LineSymbolV11; + + struct AreaSymbolV12 + { + typedef BaseSymbolV12 BaseSymbol; + typedef PointSymbolElementV12 Element; + + BaseSymbol base; + + quint32 border_symbol; + AreaSymbolCommonV8 common; + quint8 structure_variation_x; + quint8 structure_variation_y; + quint16 structure_minimum_dist; + quint16 RESERVED_MEMBER; + quint16 data_size; + + Element begin_of_elements[1]; + }; + + using TextSymbolV12 = TextSymbolV11; + + using LineTextSymbolV12 = LineTextSymbolV11; + + using RectangleSymbolV12 = RectangleSymbolV11; + + using ObjectIndexEntryV12 = ObjectIndexEntryV11; + + struct ObjectV12 + { + typedef ObjectIndexEntryV12 IndexEntryType; + + qint32 symbol; + quint8 type; + quint8 customer; + qint16 angle; + qint32 color; + quint16 line_width; + quint16 diam_flags; + quint32 server_object_id; + quint32 height; + quint64 creation_date; + quint32 multi_rep_id; + quint64 modification_date; + quint32 num_items; + quint16 num_text; + quint16 object_string_length; + quint16 db_link_length; + quint8 object_string_type; + quint8 RESERVED_MEMBER; + + OcdPoint32 coords[1]; + }; + +#pragma pack(pop) + + /** OCD file format version 11 trait. */ + struct FormatV12 + { + static constexpr int version() { return 12; } + + typedef FileHeaderV12 FileHeader; + + typedef BaseSymbolV12 BaseSymbol; + typedef PointSymbolV12 PointSymbol; + typedef LineSymbolV12 LineSymbol; + typedef AreaSymbolV12 AreaSymbol; + typedef TextSymbolV12 TextSymbol; + typedef LineTextSymbolV12 LineTextSymbol; + typedef RectangleSymbolV12 RectangleSymbol; + + typedef ObjectV12 Object; + + typedef Utf8Encoding Encoding; + }; +} + +#endif // OPENORIENTEERING_OCD_TYPES_V12_H diff --git a/src/fileformats/ocd_types_v8.h b/src/fileformats/ocd_types_v8.h index 1a3928145..dd399dd8d 100644 --- a/src/fileformats/ocd_types_v8.h +++ b/src/fileformats/ocd_types_v8.h @@ -1,5 +1,5 @@ /* - * Copyright 2013, 2015 Kai Pastor + * Copyright 2013, 2015, 2016 Kai Pastor * * This file is part of OpenOrienteering. * @@ -17,8 +17,8 @@ * along with OpenOrienteering. If not, see . */ -#ifndef _OPENORIENTEERING_OCD_TYPES_V8_ -#define _OPENORIENTEERING_OCD_TYPES_V8_ +#ifndef OPENORIENTEERING_OCD_TYPES_V8_H +#define OPENORIENTEERING_OCD_TYPES_V8_H #include "ocd_types.h" @@ -69,12 +69,8 @@ namespace Ocd SeparationInfoV8 separation_info[32]; }; - struct FileHeaderV8 + struct FileHeaderV8 : public FileHeaderGeneric { - quint16 vendor_mark; - quint16 section_mark; - quint16 version; - quint16 subversion; quint32 first_symbol_block; quint32 first_object_block; quint32 setup_pos; @@ -106,12 +102,6 @@ namespace Ocd quint8 colors[32]; PascalString<31> description; quint8 icon_bits[264]; - - enum StatusFlag - { - StatusProtected = 1, - StatusHidden = 2 - }; }; struct PointSymbolElementV8 @@ -145,13 +135,8 @@ namespace Ocd Element begin_of_elements[1]; }; - struct LineSymbolV8 + struct LineSymbolCommonV8 { - typedef BaseSymbolV8 BaseSymbol; - typedef PointSymbolElementV8 Element; - - BaseSymbol base; - quint16 line_color; quint16 line_width; quint16 line_style; @@ -175,7 +160,8 @@ namespace Ocd qint16 double_right_width; qint16 double_length; qint16 double_gap; - quint16 RESERVED_MEMBER[3]; + quint16 double_background_color_V11; /// \since V11 + quint16 RESERVED_MEMBER[2]; quint16 dec_mode; quint16 dec_last; quint16 RESERVED_MEMBER; @@ -187,9 +173,8 @@ namespace Ocd quint16 corner_data_size; quint16 start_data_size; quint16 end_data_size; - quint16 RESERVED_MEMBER; - - Element begin_of_elements[1]; + quint8 active_symbols_V11; /// \since V11 + quint8 RESERVED_MEMBER; enum LineStyleFlag { @@ -207,16 +192,21 @@ namespace Ocd DoubleBackgroundColorOn = 2 }; }; - - struct AreaSymbolV8 + + struct LineSymbolV8 { typedef BaseSymbolV8 BaseSymbol; typedef PointSymbolElementV8 Element; BaseSymbol base; - quint16 area_flags; - quint16 fill_on; + LineSymbolCommonV8 common; + + Element begin_of_elements[1]; + }; + + struct AreaSymbolCommonV8 + { quint16 fill_color; quint16 hatch_mode; quint16 hatch_color; @@ -224,46 +214,45 @@ namespace Ocd quint16 hatch_dist; qint16 hatch_angle_1; qint16 hatch_angle_2; - quint16 RESERVED_MEMBER; - quint16 structure_mode; + quint8 fill_on_V9; /// \since V12 + quint8 border_on_V9; /// \since V12 + quint8 structure_mode; + quint8 structure_draw_V12; /// \since V12 quint16 structure_width; quint16 structure_height; qint16 structure_angle; - quint16 RESERVED_MEMBER; - quint16 data_size; - - Element begin_of_elements[1]; - - enum HatchMode - { - HatchNone = 0, - HatchSingle = 1, - HatchCross = 2 - }; - - enum StructureMode - { - StructureNone = 0, - StructureAlignedRows = 1, - StructureShiftedRows = 2 - }; }; - struct TextSymbolV8 + struct AreaSymbolV8 { typedef BaseSymbolV8 BaseSymbol; + typedef PointSymbolElementV8 Element; BaseSymbol base; - PascalString<31> font_name; - quint16 font_color; + quint16 area_flags; + quint16 fill_on; + AreaSymbolCommonV8 common; + quint16 RESERVED_MEMBER; + quint16 data_size; + + Element begin_of_elements[1]; + }; + + struct BasicTextAttributesV8 + { + quint16 color; quint16 font_size; quint16 font_weight; quint8 font_italic; - quint8 charset; + quint8 charset_V8_ONLY; /// V8 text symbols only quint16 char_spacing; quint16 word_spacing; quint16 alignment; + }; + + struct SpecialTextAttributesV8 + { quint16 line_spacing; qint16 para_spacing; quint16 indent_first_line; @@ -274,15 +263,38 @@ namespace Ocd quint16 line_below_color; quint16 line_below_width; quint16 line_below_offset; - quint16 RESERVED_MEMBER; - quint16 framing_mode; - PascalString<31> framing_font; - quint16 framing_color; - quint16 framing_line_width; - quint16 framing_font_weight; - quint16 framing_italic; - quint16 framing_offset_x; - quint16 framing_offset_y; + }; + + struct FramingAttributesV8 + { + quint8 mode; /// 16 bit in V8 + quint8 line_style_V9; /// \since V9 + quint8 point_symbol_on_V10; /// \since V10 + quint32 point_symbol_number_V10; /// \since V10 + char RESERVED_MEMBER[19]; + quint16 border_left_V9; /// \since V9; TextSymbol only + quint16 border_bottom_V9; /// \since V9; TextSymbol only + quint16 border_right_V9; /// \since V9; TextSymbol only + quint16 border_top_V9; /// \since V9; TextSymbol only + quint16 color; + quint16 line_width; + quint16 font_weight; /// TextSymbol only + quint16 italic; /// TextSymbol only + quint16 offset_x; + quint16 offset_y; + }; + + struct TextSymbolV8 + { + typedef BaseSymbolV8 BaseSymbol; + + BaseSymbol base; + + PascalString<31> font_name; + BasicTextAttributesV8 basic; + SpecialTextAttributesV8 special; + quint16 RESERVED_MEMBER; + FramingAttributesV8 framing; }; struct LineTextSymbolV8 // TODO: use and test... @@ -291,23 +303,9 @@ namespace Ocd BaseSymbol base; - PascalString<31> font_name; - quint16 font_color; - quint16 font_size; - quint16 font_weight; - quint8 font_italic; - quint8 RESERVED_MEMBER; - quint16 char_spacing; - quint16 word_spacing; - quint16 alignment; - quint8 framing_mode; - quint8 RESERVED_MEMBER; - char RESERVED_MEMBER[32]; - quint16 framing_color; - quint16 framing_line_width; - quint16 RESERVED_MEMBER[2]; - quint16 framing_offset_x; - quint16 framing_offset_y; + PascalString<31> font_name; + BasicTextAttributesV8 basic; + FramingAttributesV8 framing; }; struct RectangleSymbolV8 @@ -326,7 +324,7 @@ namespace Ocd quint16 unnumbered_cells; PascalString<3> unnumbered_text; quint16 RESERVED_MEMBER; - char RESERVED_MEMBER[32]; + PascalString<31> RESERVED_MEMBER; quint16 RESERVED_MEMBER[6]; }; @@ -335,16 +333,8 @@ namespace Ocd OcdPoint32 bottom_left_bound; OcdPoint32 top_right_bound; quint32 pos; - quint16 size; + quint16 size_MISC; /// Different interpretation for version < 8 qint16 symbol; - - enum ObjectStatus - { - StatusDeleted = 0, - StatusNormal = 1, - StatusHidden = 2, - StatusDeletedForUndo = 3 - }; }; struct ObjectV8 @@ -428,13 +418,14 @@ namespace Ocd PascalDouble zoom; ZoomRectV8 zoom_history[8]; quint32 zoom_history_size; - quint16 real_coords; - char filename[256]; - quint16 hatch_areas; - quint16 dim_templates; - quint16 hide_templates; - quint16 template_mode; - qint16 template_color; + // V6 header ends here, but Mapper doesn't use the following fields. + quint16 real_coords_IGNORED; + char filename_IGNORED[256]; + quint16 hatch_areas_IGNORED; + quint16 dim_templates_IGNORED; + quint16 hide_templates_IGNORED; + quint16 template_mode_IGNORED; + qint16 template_color_IGNORED; }; #pragma pack(pop) @@ -459,17 +450,7 @@ namespace Ocd typedef ObjectV8 Object; typedef Custom8BitEncoding Encoding; - - enum SymbolType - { - TypePoint = 1, - TypeLine = 2, - TypeLineText = 2, // same as TypeLine! - TypeArea = 3, - TypeText = 4, - TypeRectangle = 5 // or formatted text... - }; }; } -#endif // _OPENORIENTEERING_OCD_TYPES_V8_ +#endif // OPENORIENTEERING_OCD_TYPES_V8_H diff --git a/src/fileformats/ocd_types_v9.h b/src/fileformats/ocd_types_v9.h index 0ac3ec09a..67f0b6a78 100644 --- a/src/fileformats/ocd_types_v9.h +++ b/src/fileformats/ocd_types_v9.h @@ -1,5 +1,5 @@ /* - * Copyright 2013, 2015 Kai Pastor + * Copyright 2013, 2015, 2016 Kai Pastor * * This file is part of OpenOrienteering. * @@ -17,26 +17,24 @@ * along with OpenOrienteering. If not, see . */ -#ifndef _OPENORIENTEERING_OCD_TYPES_V9_ -#define _OPENORIENTEERING_OCD_TYPES_V9_ +#ifndef OPENORIENTEERING_OCD_TYPES_V9_H +#define OPENORIENTEERING_OCD_TYPES_V9_H #include "ocd_types.h" +#include "ocd_types_v8.h" namespace Ocd { #pragma pack(push, 1) - struct FileHeaderV9 + struct FileHeaderV9 : public FileHeaderGeneric { - quint16 vendor_mark; - quint8 file_type; - quint8 file_status; - quint16 version; - quint16 subversion; quint32 first_symbol_block; quint32 first_object_block; - quint32 RESERVED_MEMBER[4]; + quint32 offline_sync_serial_V11; /// \since V11 + quint32 current_file_version_V12; /// \since V12 + quint32 RESERVED_MEMBER[2]; quint32 first_string_block; quint32 file_name_pos; quint32 file_name_size; @@ -67,32 +65,9 @@ namespace Ocd quint16 colors[14]; PascalString<31> description; quint8 icon_bits[484]; - - enum StatusFlag - { - StatusProtected = 1, - StatusHidden = 2 - }; }; - struct PointSymbolElementV9 - { - quint16 type; - quint16 flags; - quint16 color; - qint16 line_width; - qint16 diameter; - quint16 num_coords; - quint32 RESERVED_MEMBER; - - enum PointSymbolElementTypes - { - TypeLine = 1, - TypeArea = 2, - TypeCircle = 3, - TypeDot = 4 - }; - }; + using PointSymbolElementV9 = PointSymbolElementV8; struct PointSymbolV9 { @@ -113,60 +88,9 @@ namespace Ocd BaseSymbol base; - quint16 line_color; - quint16 line_width; - quint16 line_style; - qint16 dist_from_start; - qint16 dist_from_end; - qint16 main_length; - qint16 end_length; - qint16 main_gap; - qint16 sec_gap; - qint16 end_gap; - qint16 min_sym; - qint16 num_prim_sym; - qint16 prim_sym_dist; - quint16 double_mode; - quint16 double_flags; - quint16 double_color; - quint16 double_left_color; - quint16 double_right_color; - qint16 double_width; - qint16 double_left_width; - qint16 double_right_width; - qint16 double_length; - qint16 double_gap; - quint16 RESERVED_MEMBER[3]; - quint16 dec_mode; - quint16 dec_last; - quint16 RESERVED_MEMBER; - quint16 framing_color; - qint16 framing_width; - quint16 framing_style; - quint16 primary_data_size; - quint16 secondary_data_size; - quint16 corner_data_size; - quint16 start_data_size; - quint16 end_data_size; - quint16 RESERVED_MEMBER; + LineSymbolCommonV8 common; Element begin_of_elements[1]; - - enum LineStyleFlag - { - BevelJoin_FlatCap = 0, - RoundJoin_RoundCap = 1, - BevelJoin_PointedCap = 2, - RoundJoin_PointedCap = 3, - MiterJoin_FlatCap = 4, - MiterJoin_PointedCap = 6 - }; - - enum DoubleLineFlag - { - DoubleFillColorOn = 1, - DoubleBackgroundColorOn = 2 - }; }; struct AreaSymbolV9 @@ -177,37 +101,11 @@ namespace Ocd BaseSymbol base; quint32 border_symbol; - quint16 fill_color; - quint16 hatch_mode; - quint16 hatch_color; - quint16 hatch_line_width; - quint16 hatch_dist; - qint16 hatch_angle_1; - qint16 hatch_angle_2; - quint8 fill_on; - quint8 border_on; - quint16 structure_mode; - quint16 structure_width; - quint16 structure_height; - qint16 structure_angle; + AreaSymbolCommonV8 common; quint16 RESERVED_MEMBER; quint16 data_size; Element begin_of_elements[1]; - - enum HatchMode - { - HatchNone = 0, - HatchSingle = 1, - HatchCross = 2 - }; - - enum StructureMode - { - StructureNone = 0, - StructureAlignedRows = 1, - StructureShiftedRows = 2 - }; }; struct TextSymbolV9 @@ -216,63 +114,22 @@ namespace Ocd BaseSymbol base; - PascalString<31> font_name; - quint16 font_color; - quint16 font_size; - quint16 font_weight; - quint8 font_italic; - quint8 RESERVED_MEMBER; - quint16 char_spacing; - quint16 word_spacing; - quint16 alignment; - quint16 line_spacing; - qint16 para_spacing; - quint16 indent_first_line; - quint16 indent_other_lines; - quint16 num_tabs; - quint32 tab_pos[32]; - quint16 line_below_on; - quint16 line_below_color; - quint16 line_below_width; - quint16 line_below_offset; - quint16 RESERVED_MEMBER; - quint8 framing_mode; - quint8 framing_line_style; - char RESERVED_MEMBER[23]; - quint16 framing_border_left; - quint16 framing_border_bottom; - quint16 framing_border_right; - quint16 framing_border_top; - quint16 framing_color; - quint16 framing_line_width; - quint16 RESERVED_MEMBER[2]; - quint16 framing_offset_x; - quint16 framing_offset_y; + PascalString<31> font_name; + BasicTextAttributesV8 basic; + SpecialTextAttributesV8 special; + quint16 RESERVED_MEMBER; + FramingAttributesV8 framing; }; - struct LineTextSymbolV9 // TODO: use and test... + struct LineTextSymbolV9 { typedef BaseSymbolV9 BaseSymbol; BaseSymbol base; - PascalString<31> font_name; - quint16 font_color; - quint16 font_size; - quint16 font_weight; - quint8 font_italic; - quint8 RESERVED_MEMBER; - quint16 char_spacing; - quint16 word_spacing; - quint16 alignment; - quint8 framing_mode; - quint8 RESERVED_MEMBER; - char RESERVED_MEMBER[32]; - quint16 framing_color; - quint16 framing_line_width; - quint16 RESERVED_MEMBER[2]; - quint16 framing_offset_x; - quint16 framing_offset_y; + PascalString<31> font_name; + BasicTextAttributesV8 basic; + FramingAttributesV8 framing; }; struct RectangleSymbolV9 @@ -291,8 +148,10 @@ namespace Ocd quint16 unnumbered_cells; PascalString<3> unnumbered_text; quint16 RESERVED_MEMBER; - char RESERVED_MEMBER[32]; - quint16 RESERVED_MEMBER[6]; + PascalString<31> RESERVED_MEMBER; + quint16 RESERVED_MEMBER; + quint16 font_size_V10; /// \since V10 + quint16 RESERVED_MEMBER[4]; }; struct ObjectIndexEntryV9 @@ -303,21 +162,14 @@ namespace Ocd quint32 size; qint32 symbol; quint8 type; - quint8 RESERVED_MEMBER; + quint8 encryption_mode_V11; /// \since V11 quint8 status; quint8 view_type; quint16 color; - quint16 RESERVED_MEMBER; + quint16 group_V11; /// \since V11 quint16 layer; - quint16 RESERVED_MEMBER; - - enum ObjectStatus - { - StatusDeleted = 0, - StatusNormal = 1, - StatusHidden = 2, - StatusDeletedForUndo = 3 - }; + quint8 layout_font_V11_ONLY; /// only in V11 + quint8 RESERVED_MEMBER; }; struct ObjectV9 @@ -326,15 +178,22 @@ namespace Ocd qint32 symbol; quint8 type; - quint8 RESERVED_MEMBER; + quint8 customer_V11; /// \since V11 qint16 angle; quint32 num_items; quint16 num_text; - quint16 RESERVED_MEMBER; + quint8 mark_V11; /// \since V11 + quint8 snapping_mark_V11; /// \since V11 quint32 color; quint16 line_width; quint16 diam_flags; - quint64 RESERVED_MEMBER[2]; + // The usage of the following 16 bytes has changed significantly in the + // versions 9 to 12. This is an abstraction, capturing what seems most + // relevant. + quint32 RESERVED_MEMBER; /// V11: Server object ID + quint32 height_V11; /// \since V11; unit: 1/256 mm + quint32 RESERVED_MEMBER; + quint32 height_V10_ONLY; /// V10 only; unit: mm OcdPoint32 coords[1]; }; @@ -359,17 +218,7 @@ namespace Ocd typedef ObjectV9 Object; typedef Custom8BitEncoding Encoding; - - enum SymbolType - { - TypePoint = 1, - TypeLine = 2, - TypeArea = 3, - TypeText = 4, - TypeLineText = 6, - TypeRectangle = 7 - }; }; } -#endif // _OPENORIENTEERING_OCD_TYPES_V9_ +#endif // OPENORIENTEERING_OCD_TYPES_V9_H diff --git a/src/gdal/CMakeLists.txt b/src/gdal/CMakeLists.txt new file mode 100644 index 000000000..acb3a62e9 --- /dev/null +++ b/src/gdal/CMakeLists.txt @@ -0,0 +1,55 @@ +# +# Copyright 2016 Kai Pastor +# +# This file is part of OpenOrienteering. +# +# OpenOrienteering 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. +# +# OpenOrienteering 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 OpenOrienteering. If not, see . + +find_package(GDAL REQUIRED) +find_package(Qt5Core REQUIRED) +find_package(Qt5Gui REQUIRED) +find_package(Qt5Widgets REQUIRED) # TODO: Remove, once Symbol headers don't need it. + +qt_wrap_cpp(mapper-gdal MAPPER_GDAL_MOC + gdal_settings_page.h + ogr_file_format_p.h + ogr_template.h +) + +add_library(mapper-gdal STATIC + ${MAPPER_GDAL_MOC} + gdal_manager.h + gdal_manager.cpp + gdal_settings_page.h + gdal_settings_page.cpp + ogr_file_format.h + ogr_file_format_p.h + ogr_file_format.cpp + ogr_template.h + ogr_template.cpp +) + +target_compile_definitions(mapper-gdal PRIVATE + QT_NO_CAST_FROM_ASCII + QT_NO_CAST_TO_ASCII + QT_USE_QSTRINGBUILDER +) + +target_compile_definitions(mapper-gdal INTERFACE MAPPER_USE_GDAL) + +target_include_directories(mapper-gdal PRIVATE "${GDAL_INCLUDE_DIR}") + +target_link_libraries(mapper-gdal "${GDAL_LIBRARY}" Qt5::Core Qt5::Gui Qt5::Widgets) + +set_target_properties(mapper-gdal PROPERTIES PREFIX "") diff --git a/src/gdal/gdal_manager.cpp b/src/gdal/gdal_manager.cpp new file mode 100644 index 000000000..3f89ee839 --- /dev/null +++ b/src/gdal/gdal_manager.cpp @@ -0,0 +1,267 @@ +/* + * Copyright 2016 Kai Pastor + * + * This file is part of OpenOrienteering. + * + * OpenOrienteering 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. + * + * OpenOrienteering 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 OpenOrienteering. If not, see . + */ + +#include "gdal_manager.h" + +#include +#include + +#include +#include + +#include "../mapper_resource.h" + + + +namespace +{ + const QString gdal_manager_group{ QString::fromLatin1("GdalManager") }; + const QString gdal_configuration_group{ QString::fromLatin1("GdalConfiguration") }; + const QString gdal_dxf_key{ QString::fromLatin1("dxf") }; + const QString gdal_gpx_key{ QString::fromLatin1("gpx") }; + const QString gdal_osm_key{ QString::fromLatin1("osm") }; + +} + + + +class GdalManager::GdalManagerPrivate +{ +public: + GdalManagerPrivate() + : dirty{ true } + { + // GDAL 2.0: GDALAllRegister(); + OGRRegisterAll(); + } + + void configure() + { + if (dirty) + update(); + } + + void setFormatEnabled(GdalManager::FileFormat format, bool enabled) + { + QString key; + switch (format) + { + case GdalManager::DXF: + key = gdal_dxf_key; + break; + + case GdalManager::GPX: + key = gdal_gpx_key; + break; + + case GdalManager::OSM: + key = gdal_osm_key; + break; + } + QSettings settings; + settings.beginGroup(gdal_manager_group); + settings.setValue(key, QVariant{ enabled }); + dirty = true; + } + + bool isFormatEnabled(FileFormat format) const + { + QString key; + switch (format) + { + case GdalManager::DXF: + key = gdal_dxf_key; + break; + + case GdalManager::GPX: + key = gdal_gpx_key; + break; + + case GdalManager::OSM: + key = gdal_osm_key; + break; + } + QSettings settings; + settings.beginGroup(gdal_manager_group); + return settings.value(key).toBool(); + } + + const std::vector& supportedRasterExtensions() const + { + /// \todo + static std::vector ret; + return ret; + } + + const std::vector& supportedVectorExtensions() const + { + if (dirty) + update(); + return enabled_vector_extensions; + } + + QStringList parameterKeys() const + { + if (dirty) + update(); + return applied_parameters; + } + + QString parameterValue(const QString& key) const + { + if (dirty) + update(); + QSettings settings; + settings.beginGroup(gdal_configuration_group); + return settings.value(key).toString(); + } + + void setParameterValue(const QString& key, const QString& value) + { + QSettings settings; + settings.beginGroup(gdal_configuration_group); + settings.setValue(key, QVariant{ value }); + dirty = true; + } + + void unsetParameter(const QString& key) + { + QSettings settings; + settings.beginGroup(gdal_configuration_group); + settings.remove(key); + dirty = true; + } + +private: + void update() const + { + QSettings settings; + + /// \todo Build from driver list in GDAL/OGR >= 2.0 + static const std::vector default_extensions = { "shp", "shx" }; + enabled_vector_extensions.reserve(default_extensions.size() + 3); + enabled_vector_extensions = default_extensions; + + settings.beginGroup(gdal_manager_group); + if (settings.value(gdal_dxf_key).toBool()) + enabled_vector_extensions.push_back("dxf"); + if (settings.value(gdal_gpx_key).toBool()) + enabled_vector_extensions.push_back("gpx"); + if (settings.value(gdal_osm_key).toBool()) + enabled_vector_extensions.push_back("osm"); + settings.endGroup(); + + auto gdal_data = MapperResource::locate(MapperResource::GDAL_DATA); + if (!gdal_data.isEmpty()) + { + // The user may overwrite this default in the settings. + CPLSetConfigOption("GDAL_DATA", gdal_data.toLatin1()); + } + + settings.beginGroup(gdal_configuration_group); + QStringList new_parameters = settings.childKeys(); + if (new_parameters.isEmpty()) + { + // Default options for debugging and for some drivers + settings.setValue(QString::fromLatin1("CPL_DEBUG"), QVariant{QLatin1String("OFF")}); + settings.setValue(QString::fromLatin1("USE_PROJ_480_FEATURES"), QVariant{QLatin1String("YES")}); + settings.setValue(QString::fromLatin1("OSM_USE_CUSTOM_INDEXING"), QVariant{QLatin1String("NO")}); + new_parameters = settings.childKeys(); + } + + new_parameters.sort(); + for (auto parameter : new_parameters) + { + CPLSetConfigOption(parameter.toLatin1(), settings.value(parameter).toByteArray()); + } + for (auto parameter : static_cast(applied_parameters)) + { + if (!new_parameters.contains(parameter) + && parameter != QLatin1String{ "GDAL_DATA" }) + { + CPLSetConfigOption(parameter.toLatin1(), nullptr); + } + } + applied_parameters.swap(new_parameters); + + dirty = false; + } + + mutable bool dirty; + + mutable std::vector enabled_vector_extensions; + + mutable QStringList applied_parameters; + +}; + + + +// ### GdalManager ### + +GdalManager::GdalManager() +{ + static GdalManagerPrivate manager; + p = &manager; +} + +void GdalManager::configure() +{ + p->configure(); +} + +void GdalManager::setFormatEnabled(GdalManager::FileFormat format, bool enabled) +{ + p->setFormatEnabled(format, enabled); +} + +bool GdalManager::isFormatEnabled(GdalManager::FileFormat format) const +{ + return p->isFormatEnabled(format); +} + +const std::vector&GdalManager::supportedRasterExtensions() const +{ + return p->supportedRasterExtensions(); +} + +const std::vector& GdalManager::supportedVectorExtensions() const +{ + return p->supportedVectorExtensions(); +} + +QStringList GdalManager::parameterKeys() const +{ + return p->parameterKeys(); +} + +QString GdalManager::parameterValue(const QString& key) const +{ + return p->parameterValue(key); +} + +void GdalManager::setParameterValue(const QString& key, const QString& value) +{ + p->setParameterValue(key, value); +} + +void GdalManager::unsetParameter(const QString& key) +{ + p->unsetParameter(key); +} diff --git a/src/gdal/gdal_manager.h b/src/gdal/gdal_manager.h new file mode 100644 index 000000000..f18f559ff --- /dev/null +++ b/src/gdal/gdal_manager.h @@ -0,0 +1,109 @@ +/* + * Copyright 2016 Kai Pastor + * + * This file is part of OpenOrienteering. + * + * OpenOrienteering 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. + * + * OpenOrienteering 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 OpenOrienteering. If not, see . + */ + +#ifndef OPENORIENTEERING_GDAL_MANAGER_H +#define OPENORIENTEERING_GDAL_MANAGER_H + + +#include + +class QByteArray; +class QString; +class QStringList; + + +/** + * A utility class which takes care of GDAL settings and options. + * + * This class provides lists of extensions supported via GDAL in Mapper. + * It sets and updates GDAL configuration parameters from Mapper's settings. + * + * There is no need to keep objects of this class for an extended life time: + * instantiation is cheap; the actual state is shared and retained. + */ +class GdalManager +{ +private: + class GdalManagerPrivate; + + GdalManagerPrivate* p; + +public: + enum FileFormat + { + DXF, + GPX, + OSM + }; + + /** + * Constructs a new manager object. + */ + GdalManager(); + + /** + * Sets the GDAL configuration from Mapper's defaults and settings. + */ + void configure(); + + + /** + * Enables or disables handling of a particular file format by GDAL/OGR. + */ + void setFormatEnabled(FileFormat format, bool enabled); + + /** + * Returns if GDAL/OGR will handle a particular file format. + */ + bool isFormatEnabled(FileFormat format) const; + + + /** + * Returns the file name extensions for supported raster formats. + */ + const std::vector& supportedRasterExtensions() const; + + /** + * Returns the file name extensions for supported vector formats. + */ + const std::vector& supportedVectorExtensions() const; + + + /** + * Returns the list of GDAL configuration parameters. + */ + QStringList parameterKeys() const; + + /** + * Returns a GDAL configuration parameter value. + */ + QString parameterValue(const QString& key) const; + + /** + * Sets a GDAL configuration parameter value. + */ + void setParameterValue(const QString& key, const QString& value); + + /** + * Unsets a GDAL configuration parameter value. + */ + void unsetParameter(const QString& key); +}; + +#endif // OPENORIENTEERING_GDAL_MANAGER_H diff --git a/src/gdal/gdal_settings_page.cpp b/src/gdal/gdal_settings_page.cpp new file mode 100644 index 000000000..34093c84c --- /dev/null +++ b/src/gdal/gdal_settings_page.cpp @@ -0,0 +1,221 @@ +/* + * Copyright 2016 Kai Pastor + * + * This file is part of OpenOrienteering. + * + * OpenOrienteering 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. + * + * OpenOrienteering 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 OpenOrienteering. If not, see . + */ + + +#include "gdal_settings_page.h" + +#include +#include +#include +#include +#include + +#include "gdal_manager.h" +#include "ogr_file_format.h" +#include "../util_gui.h" +#include "../file_format_registry.h" +#include "../util/scoped_signals_blocker.h" + + +GdalSettingsPage::GdalSettingsPage(QWidget* parent) +: SettingsPage(parent) +{ + auto form_layout = new QFormLayout(); + + form_layout->addRow(Util::Headline::create(tr("Import with GDAL/OGR:"))); + + import_dxf = new QCheckBox(tr("DXF")); + form_layout->addRow(import_dxf); + + import_gpx = new QCheckBox(tr("GPX")); + form_layout->addRow(import_gpx); + + import_osm = new QCheckBox(tr("OSM")); + form_layout->addRow(import_osm); + + form_layout->addItem(Util::SpacerItem::create(this)); + form_layout->addRow(Util::Headline::create(tr("Configuration"))); + + auto layout = new QVBoxLayout(this); + + layout->addLayout(form_layout); + + parameters = new QTableWidget(1, 2); + parameters->verticalHeader()->hide(); + parameters->setHorizontalHeaderLabels({ tr("Parameter"), tr("Value") }); + auto header_view = parameters->horizontalHeader(); + header_view->setSectionResizeMode(0, QHeaderView::Stretch); + header_view->setSectionResizeMode(1, QHeaderView::Stretch); + header_view->setSectionsClickable(false); + layout->addWidget(parameters, 1); + + updateWidgets(); + + connect(parameters, &QTableWidget::cellChanged, this, &GdalSettingsPage::cellChange); +} + +GdalSettingsPage::~GdalSettingsPage() +{ + // nothing, not inlined +} + +QString GdalSettingsPage::title() const +{ + return tr("GDAL/OGR"); +} + +void GdalSettingsPage::apply() +{ + GdalManager manager; + manager.setFormatEnabled(GdalManager::DXF, import_dxf->isChecked()); + manager.setFormatEnabled(GdalManager::GPX, import_gpx->isChecked()); + manager.setFormatEnabled(GdalManager::OSM, import_osm->isChecked()); + + // The file format constructor establishes the extensions. + auto format = new OgrFileFormat(); + FileFormats.unregisterFormat(FileFormats.findFormat(format->id())); + FileFormats.registerFormat(format); + + const auto old_parameters = manager.parameterKeys(); + + QStringList new_parameters; + new_parameters.reserve(parameters->rowCount()); + for (int row = 0, end = parameters->rowCount(); row < end; ++row) + { + auto key = parameters->item(row, 0)->text().trimmed(); + if (!key.isEmpty()) + { + new_parameters.append(key); + auto value = parameters->item(row, 1)->text(); + manager.setParameterValue(key, value.trimmed()); + } + } + for (const auto key : old_parameters) + { + if (!new_parameters.contains(key)) + { + manager.unsetParameter(key); + } + } +} + +void GdalSettingsPage::reset() +{ + updateWidgets(); +} + +void GdalSettingsPage::updateWidgets() +{ + GdalManager manager; + import_dxf->setChecked(manager.isFormatEnabled(GdalManager::DXF)); + import_gpx->setChecked(manager.isFormatEnabled(GdalManager::GPX)); + import_osm->setChecked(manager.isFormatEnabled(GdalManager::OSM)); + + auto options = manager.parameterKeys(); + options.sort(); + parameters->setRowCount(options.size() + 1); + auto row = 0; + for (auto item : static_cast(options)) + { + auto key_item = new QTableWidgetItem(item); + parameters->setItem(row, 0, key_item); + auto value_item = new QTableWidgetItem(manager.parameterValue(item)); + parameters->setItem(row, 1, value_item); + ++row; + } + parameters->setRowCount(row+1); + parameters->setItem(row, 0, new QTableWidgetItem()); + parameters->setItem(row, 1, new QTableWidgetItem()); +} + +void GdalSettingsPage::cellChange(int row, int column) +{ + const QString key = parameters->item(row, 0)->text().trimmed(); + const QString value = parameters->item(row, 1)->text(); + + if (column == 1 && key.isEmpty()) + { + // Shall not happen + qWarning("Empty key for modified tag value!"); + } + else if (column == 0) + { + QSignalBlocker block(parameters); + parameters->item(row, 0)->setText(key); // trimmed + + auto last_row = parameters->rowCount() - 1; + int duplicate = findDuplicateKey(key, row); + if (key.isEmpty()) + { + if (row == last_row) + { + parameters->item(row, 1)->setText({ }); + } + else + { + parameters->model()->removeRow(row); + parameters->setCurrentCell(row, 0); + parameters->setFocus(); + } + } + else if (duplicate != row) + { + if (row == last_row) + { + parameters->item(row, 0)->setText({ }); + parameters->item(row, 0)->setText({ }); + } + else + { + parameters->model()->removeRow(row); + } + parameters->setCurrentCell(duplicate, 0); + parameters->setFocus(); + } + else + { + if (row == last_row) + { + parameters->setRowCount(last_row + 2); + parameters->setItem(last_row + 1, 0, new QTableWidgetItem()); + parameters->setItem(last_row + 1, 1, new QTableWidgetItem()); + } + + if (value.isEmpty()) + { + GdalManager manager; + parameters->item(row, 1)->setText(manager.parameterValue(key)); + } + } + } +} + +int GdalSettingsPage::findDuplicateKey(const QString& key, int row) const +{ + for (int i = 0, end = parameters->rowCount(); i < end; ++i) + { + if (i != row + && parameters->item(i, 0)->text() == key) + { + row = i; + break; + } + } + return row; +} diff --git a/src/gdal/gdal_settings_page.h b/src/gdal/gdal_settings_page.h new file mode 100644 index 000000000..3f1637df7 --- /dev/null +++ b/src/gdal/gdal_settings_page.h @@ -0,0 +1,58 @@ +/* + * Copyright 2016 Kai Pastor + * + * This file is part of OpenOrienteering. + * + * OpenOrienteering 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. + * + * OpenOrienteering 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 OpenOrienteering. If not, see . + */ + +#ifndef OPENORIENTEERING_GDAL_SETTINGS_PAGE_H +#define OPENORIENTEERING_GDAL_SETTINGS_PAGE_H + +#include "../gui/widgets/settings_page.h" + +class QCheckBox; +class QTableWidget; + + +class GdalSettingsPage : public SettingsPage +{ +Q_OBJECT +public: + explicit GdalSettingsPage(QWidget* parent = nullptr); + + ~GdalSettingsPage() override; + + QString title() const override; + + void apply() override; + + void reset() override; + +protected: + void updateWidgets(); + + void cellChange(int row, int column); + + int findDuplicateKey(const QString& key, int row) const; + +private: + QCheckBox* import_dxf; + QCheckBox* import_gpx; + QCheckBox* import_osm; + QTableWidget* parameters; +}; + + +#endif diff --git a/src/gdal/ogr_file_format.cpp b/src/gdal/ogr_file_format.cpp new file mode 100644 index 000000000..1f2111a92 --- /dev/null +++ b/src/gdal/ogr_file_format.cpp @@ -0,0 +1,1036 @@ +/* + * Copyright 2016 Kai Pastor + * + * This file is part of OpenOrienteering. + * + * OpenOrienteering 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. + * + * OpenOrienteering 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 OpenOrienteering. If not, see . + */ + +#include "ogr_file_format.h" +#include "ogr_file_format_p.h" + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "gdal_manager.h" +#include "../core/georeferencing.h" +#include "../map.h" +#include "../object_text.h" +#include "../symbol_area.h" +#include "../symbol_line.h" +#include "../symbol_point.h" +#include "../symbol_text.h" + + +namespace ogr +{ + class OGRDataSourceHDeleter + { + public: + void operator()(OGRDataSourceH data_source) const + { + OGRReleaseDataSource(data_source); + } + }; + + /** A convenience class for OGR C API datasource handles, similar to std::unique_ptr. */ + using unique_datasource = std::unique_ptr::type, OGRDataSourceHDeleter>; + + + class OGRFeatureHDeleter + { + public: + void operator()(OGRFeatureH feature) const + { + OGR_F_Destroy(feature); + } + }; + + /** A convenience class for OGR C API feature handles, similar to std::unique_ptr. */ + using unique_feature = std::unique_ptr::type, OGRFeatureHDeleter>; + +} + +namespace +{ + void applyPenWidth(OGRStyleToolH tool, LineSymbol* line_symbol) + { + int is_null; + auto pen_width = OGR_ST_GetParamDbl(tool, OGRSTPenWidth, &is_null); + if (!is_null) + { + Q_ASSERT(OGR_ST_GetUnit(tool) == OGRSTUMM); + + if (pen_width <= 0.01) + pen_width = 0.1; + + line_symbol->setLineWidth(pen_width); + } + } + + void applyPenCap(OGRStyleToolH tool, LineSymbol* line_symbol) + { + int is_null; + auto pen_cap = OGR_ST_GetParamStr(tool, OGRSTPenCap, &is_null); + if (!is_null) + { + switch (pen_cap[0]) + { + case 'p': + line_symbol->setCapStyle(LineSymbol::SquareCap); + break; + case 'r': + line_symbol->setCapStyle(LineSymbol::RoundCap); + break; + default: + ; + } + } + } + + void applyPenJoin(OGRStyleToolH tool, LineSymbol* line_symbol) + { + int is_null; + auto pen_join = OGR_ST_GetParamStr(tool, OGRSTPenJoin, &is_null); + if (!is_null) + { + switch (pen_join[0]) + { + case 'b': + line_symbol->setJoinStyle(LineSymbol::BevelJoin); + break; + case 'r': + line_symbol->setJoinStyle(LineSymbol::RoundJoin); + break; + default: + ; + } + } + } + + void applyPenPattern(OGRStyleToolH tool, LineSymbol* line_symbol) + { + int is_null; + auto raw_pattern = OGR_ST_GetParamStr(tool, OGRSTPenPattern, &is_null); + if (!is_null) + { + auto pattern = QString::fromLatin1(raw_pattern); + auto sub_pattern_re = QRegularExpression(QString::fromLatin1("([0-9.]+)([a-z]*) *([0-9.]+)([a-z]*)")); + auto match = sub_pattern_re.match(pattern); + double length_0, length_1; + bool ok = match.hasMatch(); + if (ok) + length_0 = match.capturedRef(1).toDouble(&ok); + if (ok) + length_1 = match.capturedRef(3).toDouble(&ok); + if (ok) + { + /// \todo Apply units from capture 2 and 4 + line_symbol->setDashed(true); + line_symbol->setDashLength(qMax(100, qRound(length_0 * 1000))); + line_symbol->setBreakLength(qMax(100, qRound(length_1 * 1000))); + } + else + { + qDebug("OgrFileFormat: Failed to parse dash pattern '%s'", raw_pattern); + } + } + } + + int getFontSize(const char* font_size_string) + { + auto pattern = QString::fromLatin1(font_size_string); + auto sub_pattern_re = QRegularExpression(QString::fromLatin1("([0-9.]+)([a-z]*)")); + auto match = sub_pattern_re.match(pattern); + double font_size; + bool ok = match.hasMatch(); + if (ok) + font_size = match.capturedRef(1).toDouble(&ok); + if (ok) + { + auto unit = match.capturedRef(2).toUtf8(); + if (!unit.isEmpty()) + { + if (unit == "pt") + { + + } + else if (unit == "px") + { + + } + else + { + qDebug("OgrFileFormat: Unsupported font size unit '%s'", unit.constData()); + } + } + } + else + { + qDebug("OgrFileFormat: Failed to parse font size '%s'", font_size_string); + font_size = 0; + } + return font_size; + } + + void applyLabelAnchor(int anchor, TextObject* text_object) + { + auto v_align = (anchor - 1) / 3; + switch (v_align) + { + case 0: + text_object->setVerticalAlignment(TextObject::AlignBaseline); + break; + case 1: + text_object->setVerticalAlignment(TextObject::AlignVCenter); + break; + case 2: + text_object->setVerticalAlignment(TextObject::AlignTop); + break; + case 3: + text_object->setVerticalAlignment(TextObject::AlignBottom); + break; + default: + Q_UNREACHABLE(); + } + auto h_align = (anchor - 1) % 3; + switch (h_align) + { + case 0: + text_object->setHorizontalAlignment(TextObject::AlignLeft); + break; + case 1: + text_object->setHorizontalAlignment(TextObject::AlignHCenter); + break; + case 2: + text_object->setHorizontalAlignment(TextObject::AlignRight); + break; + default: + Q_UNREACHABLE(); + } + } +} + + + +// ### OgrFileFormat ### + +OgrFileFormat::OgrFileFormat() + : FileFormat(OgrFile, "OGR", ImportExport::tr("Geospatial vector data"), QString{}, ImportSupported) +{ + for (const auto extension : GdalManager().supportedVectorExtensions()) + addExtension(QString::fromLatin1(extension)); +} + +bool OgrFileFormat::understands(const unsigned char*, size_t) const +{ + return true; +} + +Importer* OgrFileFormat::createImporter(QIODevice* stream, Map *map, MapView *view) const +{ + return new OgrFileImport(stream, map, view); +} + + + +// ### OgrFileImport ### + +OgrFileImport::OgrFileImport(QIODevice* stream, Map* map, MapView* view, bool drawing_from_projected) + : Importer(stream, map, view) + , map_srs{ OSRNewSpatialReference(nullptr) } + , manager{ OGR_SM_Create(nullptr) } + , drawing_from_projected{ drawing_from_projected } +{ + GdalManager().configure(); + + setOption(QLatin1String{ "Separate layers" }, QVariant{ false }); + + auto spec = QByteArray::fromRawData("WGS84", 6); + auto error = OSRSetWellKnownGeogCS(map_srs.get(), spec); + if (!map->getGeoreferencing().isLocal() && !error) + { + spec = map->getGeoreferencing().getProjectedCRSSpec().toLatin1(); + error = OSRImportFromProj4(map_srs.get(), spec); + } + + if (error) + { + addWarning(tr("Unable to setup \"%1\" SRS for GDAL: %2") + .arg(QString::fromLatin1(spec), QString::number(error))); + } + + // Reasonable default? + + // OGR feature style defaults + default_pen_color = new MapColor(tr("Black"), 0); + default_pen_color->setRgb({0.0, 0.0, 0.0}); + default_pen_color->setCmykFromRgb(); + map->addColor(default_pen_color, 0); + + auto default_brush_color = new MapColor(tr("Black") + QLatin1String(" 50%"), 0); + default_brush_color->setRgb({0.5, 0.5, 0.5}); + default_brush_color->setCmykFromRgb(); + map->addColor(default_brush_color, 1); + + default_point_symbol = new PointSymbol(); + default_point_symbol->setName(tr("Point")); + default_point_symbol->setNumberComponent(0, 1); + default_point_symbol->setInnerColor(default_pen_color); + map->addSymbol(default_point_symbol, 0); + + default_line_symbol = new LineSymbol(); + default_line_symbol->setName(tr("Line")); + default_line_symbol->setNumberComponent(0, 2); + default_line_symbol->setColor(default_pen_color); + default_line_symbol->setLineWidth(0.1); // (0.1 mm, nearly cosmetic) + default_line_symbol->setCapStyle(LineSymbol::FlatCap); + default_line_symbol->setJoinStyle(LineSymbol::MiterJoin); + map->addSymbol(default_line_symbol, 1); + + default_area_symbol = new AreaSymbol(); + default_area_symbol->setName(tr("Area")); + default_area_symbol->setNumberComponent(0, 3); + default_area_symbol->setColor(default_brush_color); + map->addSymbol(default_area_symbol, 2); + + default_text_symbol = new TextSymbol(); + default_text_symbol->setName(tr("Text")); + default_text_symbol->setNumberComponent(0, 4); + default_text_symbol->setColor(default_pen_color); + map->addSymbol(default_text_symbol, 3); +} + +OgrFileImport::~OgrFileImport() +{ + // nothing +} + +void OgrFileImport::import(bool load_symbols_only) +{ + auto file = qobject_cast(stream); + if (!file) + { + throw FileFormatException("Internal error"); /// \todo Review design and/or message + } + + auto filename = file->fileName(); + // GDAL 2.0: ... = GDALOpenEx(template_path.toLatin1(), GDAL_OF_VECTOR, nullptr, nullptr, nullptr); + auto data_source = ogr::unique_datasource(OGROpen(filename.toLatin1(), 0, nullptr)); + if (data_source == nullptr) + { + throw FileFormatException(Importer::tr("Could not read '%1'") + .arg(filename)); + } + + empty_geometries = 0; + no_transformation = 0; + failed_transformation = 0; + unsupported_geometry_type = 0; + too_few_coordinates = 0; + + importStyles(data_source.get()); + + if (!load_symbols_only) + { + auto num_layers = OGR_DS_GetLayerCount(data_source.get()); + for (int i = 0; i < num_layers; ++i) + { + auto layer = OGR_DS_GetLayer(data_source.get(), i); + if (!layer) + { + addWarning(tr("Unable to load layer %1.").arg(i)); + continue; + } + + auto part = map->getCurrentPart(); + if (option(QLatin1String("Separate layers")).toBool()) + { + if (num_layers > 0) + { + if (part->getNumObjects() == 0) + { + part->setName(QString::fromUtf8(OGR_L_GetName(layer))); + } + else + { + part = new MapPart(QString::fromUtf8(OGR_L_GetName(layer)), map); + auto index = map->getNumParts(); + map->addPart(part, index); + map->setCurrentPartIndex(index); + } + } + } + + importLayer(part, layer); + } + } + + if (empty_geometries) + { + addWarning(tr("Unable to load %n objects, reason: %1", nullptr, empty_geometries) + .arg(tr("Empty geometry."))); + } + if (no_transformation) + { + addWarning(tr("Unable to load %n objects, reason: %1", nullptr, no_transformation) + .arg(tr("Can't determine the coordinate transformation: %1").arg(QString::fromUtf8(CPLGetLastErrorMsg())))); + } + if (failed_transformation) + { + addWarning(tr("Unable to load %n objects, reason: %1", nullptr, failed_transformation) + .arg(tr("Failed to transform the coordinates."))); + } + if (unsupported_geometry_type) + { + addWarning(tr("Unable to load %n objects, reason: %1", nullptr, unsupported_geometry_type) + .arg(tr("Unknown or unsupported geometry type."))); + } + if (too_few_coordinates) + { + addWarning(tr("Unable to load %n objects, reason: %1", nullptr, too_few_coordinates) + .arg(tr("Not enough coordinates."))); + } +} + +void OgrFileImport::importStyles(OGRDataSourceH data_source) +{ + //auto style_table = OGR_DS_GetStyleTable(data_source); + Q_UNUSED(data_source) +} + +void OgrFileImport::importLayer(MapPart* map_part, OGRLayerH layer) +{ + Q_ASSERT(map_part); + + auto feature_definition = OGR_L_GetLayerDefn(layer); + + OGR_L_ResetReading(layer); + while (auto feature = ogr::unique_feature(OGR_L_GetNextFeature(layer))) + { + auto geometry = OGR_F_GetGeometryRef(feature.get()); + if (!geometry || OGR_G_IsEmpty(geometry)) + { + ++empty_geometries; + continue; + } + + OGR_G_FlattenTo2D(geometry); + importFeature(map_part, feature_definition, feature.get(), geometry); + } +} + +void OgrFileImport::importFeature(MapPart* map_part, OGRFeatureDefnH feature_definition, OGRFeatureH feature, OGRGeometryH geometry) +{ + to_map_coord = &OgrFileImport::fromProjected; + auto new_srs = OGR_G_GetSpatialReference(geometry); + if (new_srs && data_srs != new_srs) + { + // New SRS, indeed. + + auto transformation = ogr::unique_transformation{ OCTNewCoordinateTransformation(new_srs, map_srs.get()) }; + if (!transformation) + { + ++no_transformation; + return; + } + + // Commit change to data srs and coordinate transformation + data_srs = new_srs; + data_transform = std::move(transformation); + } + + if (new_srs) + { + auto error = OGR_G_Transform(geometry, data_transform.get()); + if (error) + { + ++failed_transformation; + return; + } + } + else if (!drawing_from_projected) + { + to_map_coord = &OgrFileImport::fromDrawing; + } + + auto object = importGeometry(map_part, feature, geometry); + + if (object && feature_definition) + { + auto num_fields = OGR_FD_GetFieldCount(feature_definition); + for (int i = 0; i < num_fields; ++i) + { + auto value = OGR_F_GetFieldAsString(feature, i); + if (value && qstrlen(value) > 0) + { + auto field_definition = OGR_FD_GetFieldDefn(feature_definition, i); + object->setTag(QString::fromUtf8(OGR_Fld_GetNameRef(field_definition)), QString::fromUtf8(value)); + } + } + } +} + +Object* OgrFileImport::importGeometry(MapPart* map_part, OGRFeatureH feature, OGRGeometryH geometry) +{ + auto geometry_type = wkbFlatten(OGR_G_GetGeometryType(geometry)); + switch (geometry_type) + { + case OGRwkbGeometryType::wkbPoint: + return importPointGeometry(map_part, feature, geometry); + + case OGRwkbGeometryType::wkbLineString: + return importLineStringGeometry(map_part, feature, geometry); + + case OGRwkbGeometryType::wkbPolygon: + return importPolygonGeometry(map_part, feature, geometry); + + case OGRwkbGeometryType::wkbGeometryCollection: + case OGRwkbGeometryType::wkbMultiLineString: + case OGRwkbGeometryType::wkbMultiPoint: + case OGRwkbGeometryType::wkbMultiPolygon: + return importGeometryCollection(map_part, feature, geometry); + + default: + qDebug("OgrFileImport: Unknown or unsupported geometry type: %d", geometry_type); + ++unsupported_geometry_type; + return nullptr; + } +} + +Object* OgrFileImport::importGeometryCollection(MapPart* map_part, OGRFeatureH feature, OGRGeometryH geometry) +{ + auto num_geometries = OGR_G_GetGeometryCount(geometry); + for (int i = 0; i < num_geometries; ++i) + { + importGeometry(map_part, feature, OGR_G_GetGeometryRef(geometry, i)); + } + return nullptr; +} + +Object* OgrFileImport::importPointGeometry(MapPart* map_part, OGRFeatureH feature, OGRGeometryH geometry) +{ + auto style = OGR_F_GetStyleString(feature); + auto symbol = getSymbol(Symbol::Point, style); + if (symbol->getType() == Symbol::Point) + { + auto object = new PointObject(symbol); + object->setPosition(toMapCoord(OGR_G_GetX(geometry, 0), OGR_G_GetY(geometry, 0))); + map_part->addObject(object); + return object; + } + else if (symbol->getType() == Symbol::Text) + { + const auto& description = symbol->getDescription(); + auto length = description.length(); + auto split = description.indexOf(QLatin1Char(' ')); + Q_ASSERT(split > 0); + Q_ASSERT(split < length); + + auto label = description.right(length - split - 1); + if (label.startsWith(QLatin1Char{'{'}) && label.endsWith(QLatin1Char{'}'})) + { + label.remove(0, 1); + label.chop(1); + int index = OGR_F_GetFieldIndex(feature, label.toLatin1()); + if (index >= 0) + { + label = QString::fromUtf8(OGR_F_GetFieldAsString(feature, index)); + } + } + if (!label.isEmpty()) + { + auto object = new TextObject(symbol); + object->setAnchorPosition(toMapCoord(OGR_G_GetX(geometry, 0), OGR_G_GetY(geometry, 0))); + // DXF observation + label.replace(QRegularExpression(QString::fromLatin1("(\\\\[^;]*;)*"), QRegularExpression::MultilineOption), QString{}); + label.replace(QLatin1String("^I"), QLatin1String("\t")); + object->setText(label); + + bool ok; + auto anchor = QStringRef(&description, 1, 2).toInt(&ok); + if (ok) + { + applyLabelAnchor(anchor, object); + } + + auto angle = QStringRef(&description, 3, split-3).toFloat(&ok); + if (ok) + { + object->setRotation(qDegreesToRadians(angle)); + } + + map_part->addObject(object); + return object; + } + } + + return nullptr; +} + +PathObject* OgrFileImport::importLineStringGeometry(MapPart* map_part, OGRFeatureH feature, OGRGeometryH geometry) +{ + geometry = OGR_G_ForceToLineString(geometry); + + auto num_points = OGR_G_GetPointCount(geometry); + if (num_points < 2) + { + ++too_few_coordinates; + return nullptr; + } + + auto style = OGR_F_GetStyleString(feature); + auto object = new PathObject(getSymbol(Symbol::Line, style)); + for (int i = 0; i < num_points; ++i) + { + object->addCoordinate(toMapCoord(OGR_G_GetX(geometry, i), OGR_G_GetY(geometry, i))); + } + map_part->addObject(object); + return object; +} + +PathObject* OgrFileImport::importPolygonGeometry(MapPart* map_part, OGRFeatureH feature, OGRGeometryH geometry) +{ + auto num_geometries = OGR_G_GetGeometryCount(geometry); + if (num_geometries < 1) + { + ++too_few_coordinates; + return nullptr; + } + + auto outline = OGR_G_ForceToLineString(OGR_G_GetGeometryRef(geometry, 0)); + auto num_points = OGR_G_GetPointCount(outline); + if (num_points < 3) + { + ++too_few_coordinates; + return nullptr; + } + + auto style = OGR_F_GetStyleString(feature); + auto object = new PathObject(getSymbol(Symbol::Area, style)); + for (int i = 0; i < num_points; ++i) + { + object->addCoordinate(toMapCoord(OGR_G_GetX(outline, i), OGR_G_GetY(outline, i))); + } + + for (int g = 1; g < num_geometries; ++g) + { + bool start_new_part = true; + auto hole = /*OGR_G_ForceToLineString*/(OGR_G_GetGeometryRef(geometry, g)); + auto num_points = OGR_G_GetPointCount(hole); + for (int i = 0; i < num_points; ++i) + { + object->addCoordinate(toMapCoord(OGR_G_GetX(hole, i), OGR_G_GetY(hole, i)), start_new_part); + start_new_part = false; + } + } + + object->closeAllParts(); + map_part->addObject(object); + return object; +} + +Symbol* OgrFileImport::getSymbol(Symbol::Type type, const char* raw_style_string) +{ + auto style_string = QByteArray::fromRawData(raw_style_string, qstrlen(raw_style_string)); + Symbol* symbol = nullptr; + switch (type) + { + case Symbol::Point: + case Symbol::Text: + symbol = point_symbols.value(style_string); + if (!symbol) + symbol = getSymbolForPointGeometry(style_string); + break; + + case Symbol::Combined: + /// \todo + // fall through + case Symbol::Line: + symbol = line_symbols.value(style_string); + if (!symbol) + symbol = getLineSymbol(style_string); + if (!symbol) + symbol = default_line_symbol; + break; + + case Symbol::Area: + symbol = area_symbols.value(style_string); + if (!symbol) + symbol = getAreaSymbol(style_string); + if (!symbol) + symbol = default_area_symbol; + break; + + case Symbol::NoSymbol: + case Symbol::AllSymbols: + Q_UNREACHABLE(); + } + + Q_ASSERT(symbol); + return symbol; +} + +MapColor* OgrFileImport::makeColor(OGRStyleToolH tool, const char* color_string) +{ + auto key = QByteArray::fromRawData(color_string, qstrlen(color_string)); + auto color = colors.value(key); + if (!color) + { + int r, g, b, a; + auto success = OGR_ST_GetRGBFromString(tool, color_string, &r, &g, &b, &a); + if (!success) + { + color = default_pen_color; + } + else if (a > 0) + { + color = new MapColor(QString::fromUtf8(color_string), map->getNumColors()); + color->setRgb(QColor{ r, g, b }); + color->setCmykFromRgb(); + map->addColor(color, map->getNumColors()); + } + + key.detach(); + colors.insert(key, color); + } + + return color; +} + +void OgrFileImport::applyPenColor(OGRStyleToolH tool, LineSymbol* line_symbol) +{ + int is_null; + auto color_string = OGR_ST_GetParamStr(tool, OGRSTPenColor, &is_null); + if (!is_null) + { + auto color = makeColor(tool, color_string); + if (color) + line_symbol->setColor(color); + else + line_symbol->setHidden(true); + } +} + +void OgrFileImport::applyBrushColor(OGRStyleToolH tool, AreaSymbol* area_symbol) +{ + int is_null; + auto color_string = OGR_ST_GetParamStr(tool, OGRSTBrushFColor, &is_null); + if (!is_null) + { + auto color = makeColor(tool, color_string); + if (color) + area_symbol->setColor(color); + else + area_symbol->setHidden(true); + } +} + + +Symbol* OgrFileImport::getSymbolForPointGeometry(const QByteArray& style_string) +{ + if (style_string.isEmpty()) + return default_point_symbol; + + auto manager = this->manager.get(); + + auto data = style_string.constData(); + if (!OGR_SM_InitStyleString(manager, data)) + return default_point_symbol; + + auto num_parts = OGR_SM_GetPartCount(manager, data); + if (!num_parts) + return default_point_symbol; + + Symbol* symbol = nullptr; + for (int i = 0; !symbol && i < num_parts; ++i) + { + auto tool = OGR_SM_GetPart(manager, i, nullptr); + if (!tool) + continue; + + OGR_ST_SetUnit(tool, OGRSTUMM, map->getScaleDenominator()); + + auto type = OGR_ST_GetType(tool); + switch (type) + { + case OGRSTCSymbol: + symbol = getSymbolForOgrSymbol(tool, style_string); + break; + + case OGRSTCLabel: + symbol = getSymbolForLabel(tool, style_string); + break; + + default: + ; + } + + OGR_ST_Destroy(tool); + } + + return symbol; +} + +LineSymbol* OgrFileImport::getLineSymbol(const QByteArray& style_string) +{ + if (style_string.isEmpty()) + return nullptr; + + auto manager = this->manager.get(); + + auto data = style_string.constData(); + if (!OGR_SM_InitStyleString(manager, data)) + return nullptr; + + auto num_parts = OGR_SM_GetPartCount(manager, data); + if (!num_parts) + return nullptr; + + LineSymbol* symbol = nullptr; + for (int i = 0; !symbol && i < num_parts; ++i) + { + auto tool = OGR_SM_GetPart(manager, i, nullptr); + if (!tool) + continue; + + OGR_ST_SetUnit(tool, OGRSTUMM, map->getScaleDenominator()); + + auto type = OGR_ST_GetType(tool); + switch (type) + { + case OGRSTCPen: + symbol = getSymbolForPen(tool, style_string); + break; + + default: + ; + } + + OGR_ST_Destroy(tool); + } + + return symbol; +} + +AreaSymbol* OgrFileImport::getAreaSymbol(const QByteArray& style_string) +{ + if (style_string.isEmpty()) + return nullptr; + + auto manager = this->manager.get(); + + auto data = style_string.constData(); + if (!OGR_SM_InitStyleString(manager, data)) + return nullptr; + + auto num_parts = OGR_SM_GetPartCount(manager, data); + if (!num_parts) + return nullptr; + + AreaSymbol* symbol = nullptr; + for (int i = 0; !symbol && i < num_parts; ++i) + { + auto tool = OGR_SM_GetPart(manager, i, nullptr); + if (!tool) + continue; + + OGR_ST_SetUnit(tool, OGRSTUMM, map->getScaleDenominator()); + + auto type = OGR_ST_GetType(tool); + switch (type) + { + case OGRSTCBrush: + symbol = getSymbolForBrush(tool, style_string); + break; + + default: + ; + } + + OGR_ST_Destroy(tool); + } + + return symbol; +} + +PointSymbol* OgrFileImport::getSymbolForOgrSymbol(OGRStyleToolH tool, const QByteArray& style_string) +{ + Q_ASSERT(OGR_ST_GetType(tool) == OGRSTCSymbol); + + auto raw_tool_key = OGR_ST_GetStyleString(tool); + auto tool_key = QByteArray::fromRawData(raw_tool_key, qstrlen(raw_tool_key)); + auto symbol = point_symbols.value(tool_key); + if (symbol && symbol->getType() == Symbol::Point) + return static_cast(symbol); + + int is_null; + auto color_string = OGR_ST_GetParamStr(tool, OGRSTSymbolColor, &is_null); + if (is_null) + return nullptr; + + auto point_symbol = static_cast(default_point_symbol->duplicate()); + auto color = makeColor(tool, color_string); + if (color) + point_symbol->setInnerColor(color); + else + point_symbol->setHidden(true); + + auto key = style_string; + key.detach(); + point_symbols.insert(key, point_symbol); + + if (key != tool_key) + { + tool_key.detach(); + point_symbols.insert(tool_key, point_symbol); + } + + map->addSymbol(point_symbol, map->getNumSymbols()); + return point_symbol; +} + +TextSymbol* OgrFileImport::getSymbolForLabel(OGRStyleToolH tool, const QByteArray&) +{ + Q_ASSERT(OGR_ST_GetType(tool) == OGRSTCLabel); + + int is_null; + auto label_string = OGR_ST_GetParamStr(tool, OGRSTLabelTextString, &is_null); + if (is_null) + return nullptr; + + auto color_string = OGR_ST_GetParamStr(tool, OGRSTLabelFColor, &is_null); + auto font_size_string = OGR_ST_GetParamStr(tool, OGRSTLabelSize, &is_null); + + // Don't use the style string as a key: The style contains the label. + QByteArray key; + key.reserve(qstrlen(color_string) + qstrlen(font_size_string) + 1); + key.append(color_string); + key.append(font_size_string); + auto text_symbol = static_cast(text_symbols.value(key)); + if (!text_symbol) + { + text_symbol = static_cast(default_text_symbol->duplicate()); + + auto color = makeColor(tool, color_string); + if (color) + text_symbol->setColor(color); + else + text_symbol->setHidden(true); + + auto font_size = OGR_ST_GetParamDbl(tool, OGRSTLabelSize, &is_null); + if (!is_null && font_size > 0.0) + text_symbol->scale(font_size / text_symbol->getFontSize()); + + key.detach(); + text_symbols.insert(key, text_symbol); + + map->addSymbol(text_symbol, map->getNumSymbols()); + } + + auto anchor = qBound(1, OGR_ST_GetParamNum(tool, OGRSTLabelAnchor, &is_null), 12); + if (is_null) + anchor = 1; + + auto angle = OGR_ST_GetParamDbl(tool, OGRSTLabelAngle, &is_null); + if (is_null) + angle = 0.0; + + QString description; + description.reserve(qstrlen(label_string) + 100); + description.append(QString::number(100 + anchor)); + description.append(QString::number(angle, 'g', 1)); + description.append(QLatin1Char(' ')); + description.append(QString::fromUtf8(label_string)); + text_symbol->setDescription(description); + + return text_symbol; +} + +LineSymbol* OgrFileImport::getSymbolForPen(OGRStyleToolH tool, const QByteArray& style_string) +{ + Q_ASSERT(OGR_ST_GetType(tool) == OGRSTCPen); + + auto raw_tool_key = OGR_ST_GetStyleString(tool); + auto tool_key = QByteArray::fromRawData(raw_tool_key, qstrlen(raw_tool_key)); + auto symbol = line_symbols.value(tool_key); + if (symbol && symbol->getType() == Symbol::Line) + return static_cast(symbol); + + auto line_symbol = static_cast(default_line_symbol->duplicate()); + applyPenColor(tool, line_symbol); + applyPenWidth(tool, line_symbol); + applyPenCap(tool, line_symbol); + applyPenJoin(tool, line_symbol); + applyPenPattern(tool, line_symbol); + + auto key = style_string; + key.detach(); + line_symbols.insert(key, line_symbol); + + if (key != tool_key) + { + tool_key.detach(); + line_symbols.insert(tool_key, line_symbol); + } + + map->addSymbol(line_symbol, map->getNumSymbols()); + return line_symbol; +} + +AreaSymbol* OgrFileImport::getSymbolForBrush(OGRStyleToolH tool, const QByteArray& style_string) +{ + Q_ASSERT(OGR_ST_GetType(tool) == OGRSTCBrush); + + auto raw_tool_key = OGR_ST_GetStyleString(tool); + auto tool_key = QByteArray::fromRawData(raw_tool_key, qstrlen(raw_tool_key)); + auto symbol = area_symbols.value(tool_key); + if (symbol && symbol->getType() == Symbol::Area) + return static_cast(symbol); + + auto area_symbol = static_cast(default_area_symbol->duplicate()); + applyBrushColor(tool, area_symbol); + + auto key = style_string; + key.detach(); + area_symbols.insert(key, area_symbol); + + if (key != tool_key) + { + tool_key.detach(); + area_symbols.insert(tool_key, area_symbol); + } + + map->addSymbol(area_symbol, map->getNumSymbols()); + return area_symbol; +} + + +MapCoord OgrFileImport::fromDrawing(double x, double y) const +{ + return { x, -y }; +} + +MapCoord OgrFileImport::fromProjected(double x, double y) const +{ + return map->getGeoreferencing().toMapCoords(QPointF{ x, y }); +} diff --git a/src/gdal/ogr_file_format.h b/src/gdal/ogr_file_format.h new file mode 100644 index 000000000..64e41841f --- /dev/null +++ b/src/gdal/ogr_file_format.h @@ -0,0 +1,55 @@ +/* + * Copyright 2016 Kai Pastor + * + * This file is part of OpenOrienteering. + * + * OpenOrienteering 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. + * + * OpenOrienteering 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 OpenOrienteering. If not, see . + */ + +#ifndef OPENORIENTEERING_OGR_FILE_FORMAT_H +#define OPENORIENTEERING_OGR_FILE_FORMAT_H + +#include "../file_format.h" + +/** + * A FileFormat for geospatial vector data supported by OGR. + * + * Geospatial vector data cannot be loaded as a regular (OpenOrienteering) Map + * because it has no scale. However, it typically has a spatial reference, and + * so it can be imported into an existing map. This is the major reason for + * implementing the OGR support as a FileFormat. + */ +class OgrFileFormat : public FileFormat +{ +public: + /** + * Constructs a new OgrFileFormat. + */ + OgrFileFormat(); + + /** + * Always returns true. + * + * There is no cheap way to determine the answer via OGR. + */ + bool understands(const unsigned char *, size_t) const override; + + /** + * Creates an importer object and configures it for the given input stream + * and output map and view. + */ + Importer* createImporter(QIODevice* stream, Map *map, MapView *view) const override; +}; + +#endif // OPENORIENTEERING_OGR_FILE_FORMAT_H diff --git a/src/gdal/ogr_file_format_p.h b/src/gdal/ogr_file_format_p.h new file mode 100644 index 000000000..a9ab6403d --- /dev/null +++ b/src/gdal/ogr_file_format_p.h @@ -0,0 +1,214 @@ +/* + * Copyright 2016 Kai Pastor + * + * This file is part of OpenOrienteering. + * + * OpenOrienteering 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. + * + * OpenOrienteering 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 OpenOrienteering. If not, see . + */ + +#ifndef OPENORIENTEERING_OGR_FILE_FORMAT_P_H +#define OPENORIENTEERING_OGR_FILE_FORMAT_P_H + +#include + +#include +#include + +// The GDAL/OGR C API is more stable than the C++ API. +#include +#include + +#include "../core/map_coord.h" +#include "../file_import_export.h" +#include "../symbol.h" + +class AreaSymbol; +class LineSymbol; +class MapColor; +class MapPart; +class Object; +class PathObject; +class PointObject; +class PointSymbol; +class TextSymbol; + + +namespace ogr +{ + class OGRCoordinateTransformationHDeleter + { + public: + void operator()(OGRCoordinateTransformationH ct) const + { + OCTDestroyCoordinateTransformation(ct); + } + }; + + /** + * A convenience class for OGR C API coordinate transformation handles, + * similar to std::unique_ptr. + */ + using unique_transformation = std::unique_ptr::type, OGRCoordinateTransformationHDeleter>; + + + class OGRSpatialReferenceHDeleter + { + public: + void operator()(OGRSpatialReferenceH srs) const + { + OSRDestroySpatialReference(srs); + } + }; + + /** + * A convenience class for OGR C API SRS handles, similar to std::unique_ptr. + */ + using unique_srs = std::unique_ptr::type, OGRSpatialReferenceHDeleter>; + + + class OGRStyleMgrHDeleter + { + public: + void operator()(OGRStyleMgrH manager) const + { + OGR_SM_Destroy(manager); + } + }; + + /** A convenience class for OGR C API feature handles, similar to std::unique_ptr. */ + using unique_stylemanager = std::unique_ptr::type, OGRStyleMgrHDeleter>; +} + + + +/** + * An Importer for geospatial vector data supported by OGR. + * + * OGR needs to know the filename. The filename can be either derived from + * a QFile passed as stream to the constructor, or set directly through the + * option "filename". + * + * The option "separate_layers" will cause OGR layers to be imported as distinct + * map parts if set to true. + */ +class OgrFileImport : public Importer +{ +Q_OBJECT +public: + /** + * A Pointer to a function which creates a MapCoordF from double coordinates. + */ + using MapCoordConstructor = MapCoord (OgrFileImport::*)(double, double) const; + + /** + * Constructs a new importer. + */ + OgrFileImport(QIODevice* stream, Map *map, MapView *view, bool drawing_from_projected = false); + + ~OgrFileImport() override; + +protected: + void import(bool load_symbols_only) override; + + void importStyles(OGRDataSourceH data_source); + + void importLayer(MapPart* map_part, OGRLayerH layer); + + void importFeature(MapPart* map_part, OGRFeatureDefnH feature_definition, OGRFeatureH feature, OGRGeometryH geometry); + + Object* importGeometry(MapPart* map_part, OGRFeatureH feature, OGRGeometryH geometry); + + Object* importGeometryCollection(MapPart* map_part, OGRFeatureH feature, OGRGeometryH geometry); + + Object* importPointGeometry(MapPart* map_part, OGRFeatureH feature, OGRGeometryH geometry); + + PathObject* importLineStringGeometry(MapPart* map_part, OGRFeatureH feature, OGRGeometryH geometry); + + PathObject* importPolygonGeometry(MapPart* map_part, OGRFeatureH feature, OGRGeometryH geometry); + + + Symbol* getSymbol(Symbol::Type type, const char* raw_style_string); + + MapColor* makeColor(OGRStyleToolH tool, const char* color_string); + + void applyPenColor(OGRStyleToolH tool, LineSymbol* line_symbol); + + void applyBrushColor(OGRStyleToolH tool, AreaSymbol* area_symbol); + + + MapCoord toMapCoord(double x, double y) const; + + /** + * A MapCoordConstructor which interpretes the given coordinates in millimeters on paper. + */ + MapCoord fromDrawing(double x, double y) const; + + /** + * A MapCoordConstructor which interpretes the given coordinates as projected. + */ + MapCoord fromProjected(double x, double y) const; + +private: + Symbol* getSymbolForPointGeometry(const QByteArray& style_string); + LineSymbol* getLineSymbol(const QByteArray& style_string); + AreaSymbol* getAreaSymbol(const QByteArray& style_string); + + PointSymbol* getSymbolForOgrSymbol(OGRStyleToolH tool, const QByteArray& style_string); + TextSymbol* getSymbolForLabel(OGRStyleToolH tool, const QByteArray& style_string); + LineSymbol* getSymbolForPen(OGRStyleToolH tool, const QByteArray& style_string); + AreaSymbol* getSymbolForBrush(OGRStyleToolH tool, const QByteArray& style_string); + + QHash point_symbols; + PointSymbol* default_point_symbol; + QHash text_symbols; + TextSymbol* default_text_symbol; + QHash line_symbols; + LineSymbol* default_line_symbol; + QHash area_symbols; + AreaSymbol* default_area_symbol; + QHash colors; + MapColor* default_pen_color; + + MapCoordConstructor to_map_coord; + + ogr::unique_srs map_srs; + + OGRSpatialReferenceH data_srs; + + ogr::unique_transformation data_transform; + + ogr::unique_stylemanager manager; + + unsigned int empty_geometries; + unsigned int no_transformation; + unsigned int failed_transformation; + unsigned int unsupported_geometry_type; + unsigned int too_few_coordinates; + + bool drawing_from_projected; +}; + + + +// ### inline code ### + +inline +MapCoord OgrFileImport::toMapCoord(double x, double y) const +{ + return (this->*to_map_coord)(x, y); +} + + + +#endif // OPENORIENTEERING_OGR_FILE_FORMAT_P_H diff --git a/src/gdal/ogr_template.cpp b/src/gdal/ogr_template.cpp new file mode 100644 index 000000000..6f44f657b --- /dev/null +++ b/src/gdal/ogr_template.cpp @@ -0,0 +1,119 @@ +/* + * Copyright 2016 Kai Pastor + * + * This file is part of OpenOrienteering. + * + * OpenOrienteering 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. + * + * OpenOrienteering 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 OpenOrienteering. If not, see . + */ + +#include "ogr_template.h" + +#include +#include + +#include "gdal_manager.h" +#include "ogr_file_format_p.h" +#include "../map.h" +#include "../object.h" + + +const std::vector& OgrTemplate::supportedExtensions() +{ + return GdalManager().supportedVectorExtensions(); +} + + +OgrTemplate::OgrTemplate(const QString& path, Map* map) +: TemplateMap(path, map) +, migrating_from_template_track(false) +{ + // nothing else +} + +OgrTemplate::~OgrTemplate() +{ + if (template_state == Loaded) + unloadTemplateFile(); +} + + +const char* OgrTemplate::getTemplateType() const +{ + return "OgrTemplate"; +} + + +bool OgrTemplate::loadTemplateFileImpl(bool configuring) +{ + Q_UNUSED(configuring); + + std::unique_ptr new_template_map{ new Map() }; + new_template_map->setGeoreferencing(map->getGeoreferencing()); + + QFile stream{ template_path }; + try + { + OgrFileImport importer{ &stream, new_template_map.get(), nullptr, migrating_from_template_track }; + importer.doImport(false, template_path); + setTemplateMap(std::move(new_template_map)); + + if (!importer.warnings().empty()) + { + QString message; + message.reserve((importer.warnings().back().length()+1) * importer.warnings().size()); + for (auto& warning : importer.warnings()) + { + message.append(warning); + message.append(QLatin1Char{'\n'}); + } + message.chop(1); + setErrorString(message); + } + + return true; + } + catch (FileFormatException& e) + { + setErrorString(QString::fromUtf8(e.what())); + return false; + } +} + + +Template* OgrTemplate::duplicateImpl() const +{ + OgrTemplate* copy = new OgrTemplate(template_path, map); + if (template_state == Loaded) + copy->loadTemplateFileImpl(false); + return copy; +} + + +bool OgrTemplate::loadTypeSpecificTemplateConfiguration(QXmlStreamReader& xml) +{ + if (xml.name() == QLatin1String("crs_spec")) + { + migrating_from_template_track = true; + } + xml.skipCurrentElement(); + return true; +} + +void OgrTemplate::saveTypeSpecificTemplateConfiguration(QXmlStreamWriter& xml) const +{ + if (migrating_from_template_track) + { + xml.writeEmptyElement(QLatin1String("crs_spec")); + } +} diff --git a/src/gdal/ogr_template.h b/src/gdal/ogr_template.h new file mode 100644 index 000000000..45aa39da4 --- /dev/null +++ b/src/gdal/ogr_template.h @@ -0,0 +1,59 @@ +/* + * Copyright 2016 Kai Pastor + * + * This file is part of OpenOrienteering. + * + * OpenOrienteering 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. + * + * OpenOrienteering 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 OpenOrienteering. If not, see . + */ + +#ifndef OPENORIENTEERING_OGR_TEMPLATE_H +#define OPENORIENTEERING_OGR_TEMPLATE_H + +#include "../template_map.h" + +#include "../core/georeferencing.h" + + +/** + * Template displaying a file supported by OGR. + */ +class OgrTemplate : public TemplateMap +{ +Q_OBJECT +public: + static const std::vector& supportedExtensions(); + + + OgrTemplate(const QString& path, Map* map); + + ~OgrTemplate() override; + + + const char* getTemplateType() const override; + + + bool loadTemplateFileImpl(bool configuring) override; + +protected: + Template* duplicateImpl() const override; + + bool loadTypeSpecificTemplateConfiguration(QXmlStreamReader& xml) override; + + void saveTypeSpecificTemplateConfiguration(QXmlStreamWriter& xml) const override; + +private: + bool migrating_from_template_track; +}; + +#endif // OPENORIENTEERING_OGR_TEMPLATE_H diff --git a/src/global.cpp b/src/global.cpp index b08b4f530..b918c6746 100644 --- a/src/global.cpp +++ b/src/global.cpp @@ -27,12 +27,16 @@ #include "file_format_native.h" #include "file_format_xml.h" #include "fileformats/ocd_file_format.h" +#include "gdal/ogr_file_format.h" void doStaticInitializations() { // Register the supported file formats FileFormats.registerFormat(new XMLFileFormat()); FileFormats.registerFormat(new OcdFileFormat()); +#ifdef MAPPER_USE_GDAL + FileFormats.registerFormat(new OgrFileFormat()); +#endif #ifndef NO_NATIVE_FILE_FORMAT FileFormats.registerFormat(new NativeFileFormat()); // TODO: Remove before release 1.0 #endif diff --git a/src/gps_display.cpp b/src/gps_display.cpp index e08ac84bf..cab257960 100644 --- a/src/gps_display.cpp +++ b/src/gps_display.cpp @@ -1,6 +1,6 @@ /* * Copyright 2013 Thomas Schöps - * Copyright 2014 Kai Pastor + * Copyright 2014, 2016 Kai Pastor * * This file is part of OpenOrienteering. * @@ -27,43 +27,41 @@ # include # include #endif -#include -#include #include +#include #include #include "core/georeferencing.h" +#include "compass.h" #include "map_widget.h" #include "util.h" -#include "compass.h" +#include "util/backports.h" -GPSDisplay::GPSDisplay(MapWidget* widget, const Georeferencing& georeferencing) - : QObject() - , visible(false) - , source(NULL) +GPSDisplay::GPSDisplay(MapWidget* widget, const Georeferencing& georeferencing, QObject* parent) + : QObject(parent) , widget(widget) , georeferencing(georeferencing) + , source(nullptr) + , tracking_lost(false) + , has_valid_position(false) + , gps_updated(false) + , visible(false) + , distance_rings_enabled(false) + , heading_indicator_enabled(false) { - gps_updated = false; - tracking_lost = false; - has_valid_position = false; - - distance_rings_enabled = false; - heading_indicator_enabled = false; - #if defined(QT_POSITIONING_LIB) source = QGeoPositionInfoSource::createDefaultSource(this); if (!source) { - qDebug() << "Cannot create QGeoPositionInfoSource!"; + qDebug("Cannot create QGeoPositionInfoSource!"); return; } source->setPreferredPositioningMethods(QGeoPositionInfoSource::SatellitePositioningMethods); source->setUpdateInterval(1000); - connect(source, SIGNAL(positionUpdated(const QGeoPositionInfo&)), this, SLOT(positionUpdated(const QGeoPositionInfo&)), Qt::QueuedConnection); - connect(source, SIGNAL(error(QGeoPositionInfoSource::Error)), this, SLOT(error(QGeoPositionInfoSource::Error))); - connect(source, SIGNAL(updateTimeout()), this, SLOT(updateTimeout())); + connect(source, &QGeoPositionInfoSource::positionUpdated, this, &GPSDisplay::positionUpdated, Qt::QueuedConnection); + connect(source, QOverload::of(&QGeoPositionInfoSource::error), this, &GPSDisplay::error); + connect(source, &QGeoPositionInfoSource::updateTimeout, this, &GPSDisplay::updateTimeout); #elif defined(MAPPER_DEVELOPMENT_BUILD) // DEBUG QTimer* debug_timer = new QTimer(this); @@ -78,7 +76,7 @@ GPSDisplay::GPSDisplay(MapWidget* widget, const Georeferencing& georeferencing) GPSDisplay::~GPSDisplay() { stopUpdates(); - widget->setGPSDisplay(NULL); + widget->setGPSDisplay(nullptr); } bool GPSDisplay::checkGPSEnabled() @@ -172,12 +170,11 @@ void GPSDisplay::paint(QPainter* painter) painter->setBrush(QBrush(tracking_lost ? Qt::gray : Qt::red)); if (heading_indicator_enabled) { - const qreal arrow_length = Util::mmToPixelLogical(1.5f); - const qreal heading_indicator_length = Util::mmToPixelLogical(9999.0f); // very long + const qreal base_length_unit = Util::mmToPixelLogical(0.6); // For heading indicator, get azimuth from compass and calculate // the relative rotation to map view rotation, clockwise. - float heading_rotation_deg = Compass::getInstance().getCurrentAzimuth() + 180.0f / M_PI * widget->getMapView()->getRotation(); + qreal heading_rotation_deg = Compass::getInstance().getCurrentAzimuth() + qRadiansToDegrees(widget->getMapView()->getRotation()); painter->save(); painter->translate(gps_pos); @@ -185,17 +182,17 @@ void GPSDisplay::paint(QPainter* painter) // Draw arrow static const QPointF arrow_points[4] = { - QPointF(0, -arrow_length), - QPointF(0.4f * arrow_length, 0.4f * arrow_length), + QPointF(0, -2.5 * base_length_unit), + QPointF(base_length_unit, base_length_unit), QPointF(0, 0), - QPointF(-0.4f * arrow_length, 0.4f * arrow_length) + QPointF(base_length_unit, base_length_unit) }; painter->drawPolygon(arrow_points, 4); // Draw heading line - painter->setPen(QPen(Qt::gray, Util::mmToPixelLogical(0.1f))); + painter->setPen(QPen(Qt::gray, base_length_unit / 6)); painter->setBrush(Qt::NoBrush); - painter->drawLine(QPointF(0, 0), QPointF(0, -1 * heading_indicator_length)); + painter->drawLine(QPointF(0, 0), QPointF(0, -10000 * base_length_unit)); // very long painter->restore(); } @@ -205,27 +202,28 @@ void GPSDisplay::paint(QPainter* painter) painter->drawEllipse(gps_pos, dot_radius, dot_radius); } + auto meters_to_pixels = widget->getMapView()->lengthToPixel(qreal(1000000) / georeferencing.getScaleDenominator()); // Draw distance circles if (distance_rings_enabled) { const int num_distance_rings = 2; - const float distance_ring_radius_meters = 10; + const qreal distance_ring_radius_meters = 10; - float distance_ring_radius_pixels = widget->getMapView()->lengthToPixel(100000.0 * distance_ring_radius_meters / georeferencing.getScaleDenominator()); - painter->setPen(QPen(Qt::gray, Util::mmToPixelLogical(0.1f))); + auto distance_ring_radius_pixels = distance_ring_radius_meters * meters_to_pixels; + painter->setPen(QPen(Qt::gray, Util::mmToPixelLogical(0.1))); painter->setBrush(Qt::NoBrush); - for (int i = 0; i < num_distance_rings; ++ i) + auto radius = distance_ring_radius_pixels; + for (int i = 0; i < num_distance_rings; ++i) { - float radius = (i + 1) * distance_ring_radius_pixels; painter->drawEllipse(gps_pos, radius, radius); + radius += distance_ring_radius_pixels; } } // Draw accuracy circle if (latest_gps_coord_accuracy >= 0) { - float accuracy_meters = latest_gps_coord_accuracy; - float accuracy_pixels = widget->getMapView()->lengthToPixel(1000000.0 * accuracy_meters / georeferencing.getScaleDenominator()); + auto accuracy_pixels = latest_gps_coord_accuracy * meters_to_pixels; painter->setPen(QPen(tracking_lost ? Qt::gray : Qt::red, Util::mmToPixelLogical(0.2f))); painter->setBrush(Qt::NoBrush); @@ -286,7 +284,7 @@ void GPSDisplay::updateTimeout() void GPSDisplay::debugPositionUpdate() { #if MAPPER_DEVELOPMENT_BUILD - if (! visible) + if (!visible) return; QTime now = QTime::currentTime(); @@ -344,17 +342,16 @@ MapCoordF GPSDisplay::calcLatestGPSCoord(bool& ok) latest_gps_coord = georeferencing.toMapCoordF(latlon, &ok); if (!ok) { - qDebug() << "GPSDisplay::calcLatestGPSCoord(): Cannot convert LatLon to MapCoordF!"; + qDebug("GPSDisplay::calcLatestGPSCoord(): Cannot convert LatLon to MapCoordF!"); return latest_gps_coord; } gps_updated = false; ok = true; - return latest_gps_coord; #else ok = has_valid_position; - return latest_gps_coord; #endif + return latest_gps_coord; } void GPSDisplay::updateMapWidget() diff --git a/src/gps_display.h b/src/gps_display.h index 92d13200a..2101c4f96 100644 --- a/src/gps_display.h +++ b/src/gps_display.h @@ -1,5 +1,6 @@ /* * Copyright 2013 Thomas Schöps + * Copyright 2016 Kai Pastor * * This file is part of OpenOrienteering. * @@ -31,11 +32,12 @@ QT_BEGIN_NAMESPACE class QPainter; +class QGeoPositionInfo; +class QGeoPositionInfoSource; QT_END_NAMESPACE + class MapWidget; class Georeferencing; -class QGeoPositionInfo; -class QGeoPositionInfoSource; /** @@ -46,9 +48,9 @@ class GPSDisplay : public QObject Q_OBJECT public: /// Creates a GPS display for the given map widget and georeferencing. - GPSDisplay(MapWidget* widget, const Georeferencing& georeferencing); + GPSDisplay(MapWidget* widget, const Georeferencing& georeferencing, QObject* parent = nullptr); /// Destructor, removes the GPS display from the map widget. - virtual ~GPSDisplay(); + ~GPSDisplay() override; /** * @brief Checks if GPS is enabled and may guide the user to the device settings. @@ -115,7 +117,9 @@ private slots: MapCoordF calcLatestGPSCoord(bool& ok); void updateMapWidget(); - bool gps_updated; + MapWidget* widget; + const Georeferencing& georeferencing; + QGeoPositionInfoSource* source; #if defined(QT_POSITIONING_LIB) QGeoPositionInfo latest_pos_info; #endif @@ -123,14 +127,10 @@ private slots: float latest_gps_coord_accuracy; bool tracking_lost; bool has_valid_position; - + bool gps_updated; bool visible; bool distance_rings_enabled; bool heading_indicator_enabled; - - QGeoPositionInfoSource* source; - MapWidget* widget; - const Georeferencing& georeferencing; }; #endif diff --git a/src/gps_track.cpp b/src/gps_track.cpp index 6f5db0f14..fc79eab71 100644 --- a/src/gps_track.cpp +++ b/src/gps_track.cpp @@ -39,7 +39,7 @@ namespace { // Shared definition of standard geographic CRS. // TODO: Merge with Georeferencing. - static const QString geographic_crs_spec = "+proj=latlong +datum=WGS84"; + static const QString geographic_crs_spec = QString::fromLatin1("+proj=latlong +datum=WGS84"); } @@ -62,17 +62,17 @@ TrackPoint::TrackPoint(LatLon coord, QDateTime datetime, float elevation, int nu } void TrackPoint::save(QXmlStreamWriter* stream) const { - stream->writeAttribute("lat", QString::number(gps_coord.latitude(), 'f', 12)); - stream->writeAttribute("lon", QString::number(gps_coord.longitude(), 'f', 12)); + stream->writeAttribute(QStringLiteral("lat"), QString::number(gps_coord.latitude(), 'f', 12)); + stream->writeAttribute(QStringLiteral("lon"), QString::number(gps_coord.longitude(), 'f', 12)); if (datetime.isValid()) - stream->writeTextElement("time", datetime.toString(Qt::ISODate) + 'Z'); + stream->writeTextElement(QStringLiteral("time"), datetime.toString(Qt::ISODate) + QLatin1Char('Z')); if (elevation > -9999) - stream->writeTextElement("ele", QString::number(elevation, 'f', 3)); + stream->writeTextElement(QStringLiteral("ele"), QString::number(elevation, 'f', 3)); if (num_satellites >= 0) - stream->writeTextElement("sat", QString::number(num_satellites)); + stream->writeTextElement(QStringLiteral("sat"), QString::number(num_satellites)); if (hDOP >= 0) - stream->writeTextElement("hdop", QString::number(hDOP, 'f', 3)); + stream->writeTextElement(QStringLiteral("hdop"), QString::number(hDOP, 'f', 3)); } @@ -161,17 +161,17 @@ bool Track::loadFrom(const QString& path, bool project_points, QWidget* dialog_p clear(); - if (path.endsWith(".gpx", Qt::CaseInsensitive)) + if (path.endsWith(QLatin1String(".gpx"), Qt::CaseInsensitive)) { if (!loadFromGPX(&file, project_points, dialog_parent)) return false; } - else if (path.endsWith(".dxf", Qt::CaseInsensitive)) + else if (path.endsWith(QLatin1String(".dxf"), Qt::CaseInsensitive)) { if (!loadFromDXF(&file, project_points, dialog_parent)) return false; } - else if (path.endsWith(".osm", Qt::CaseInsensitive)) + else if (path.endsWith(QLatin1String(".osm"), Qt::CaseInsensitive)) { if (!loadFromOSM(&file, project_points, dialog_parent)) return false; @@ -190,28 +190,28 @@ bool Track::saveTo(const QString& path) const QXmlStreamWriter stream(&file); stream.writeStartDocument(); - stream.writeStartElement("gpx"); - stream.writeAttribute("version", "1.1"); - stream.writeAttribute("creator", APP_NAME); + stream.writeStartElement(QString::fromLatin1("gpx")); + stream.writeAttribute(QString::fromLatin1("version"), QString::fromLatin1("1.1")); + stream.writeAttribute(QString::fromLatin1("creator"), APP_NAME); int size = getNumWaypoints(); for (int i = 0; i < size; ++i) { - stream.writeStartElement("wpt"); + stream.writeStartElement(QStringLiteral("wpt")); const TrackPoint& point = getWaypoint(i); point.save(&stream); - stream.writeTextElement("name", waypoint_names[i]); + stream.writeTextElement(QStringLiteral("name"), waypoint_names[i]); stream.writeEndElement(); } - stream.writeStartElement("trk"); + stream.writeStartElement(QStringLiteral("trk")); for (int i = 0; i < getNumSegments(); ++i) { - stream.writeStartElement("trkseg"); + stream.writeStartElement(QStringLiteral("trkseg")); size = getSegmentPointCount(i); for (int k = 0; k < size; ++k) { - stream.writeStartElement("trkpt"); + stream.writeStartElement(QStringLiteral("trkpt")); const TrackPoint& point = getSegmentPoint(i, k); point.save(&stream); stream.writeEndElement(); @@ -347,7 +347,7 @@ bool Track::loadFromGPX(QFile* file, bool project_points, QWidget* dialog_parent Q_UNUSED(dialog_parent); track_crs = new Georeferencing(); - track_crs->setProjectedCRS("", geographic_crs_spec); + track_crs->setProjectedCRS({}, geographic_crs_spec); track_crs->setTransformationDirectly(QTransform()); TrackPoint point; @@ -359,18 +359,18 @@ bool Track::loadFromGPX(QFile* file, bool project_points, QWidget* dialog_parent stream.readNext(); if (stream.tokenType() == QXmlStreamReader::StartElement) { - if (stream.name().compare("wpt", Qt::CaseInsensitive) == 0 || - stream.name().compare("trkpt", Qt::CaseInsensitive) == 0 || - stream.name().compare("rtept", Qt::CaseInsensitive) == 0) + if (stream.name().compare(QLatin1String("wpt"), Qt::CaseInsensitive) == 0 + || stream.name().compare(QLatin1String("trkpt"), Qt::CaseInsensitive) == 0 + || stream.name().compare(QLatin1String("rtept"), Qt::CaseInsensitive) == 0) { - point = TrackPoint(LatLon(stream.attributes().value("lat").toString().toDouble(), - stream.attributes().value("lon").toString().toDouble())); + point = TrackPoint(LatLon(stream.attributes().value(QLatin1String("lat")).toDouble(), + stream.attributes().value(QLatin1String("lon")).toDouble())); if (project_points) point.map_coord = map_georef.toMapCoordF(point.gps_coord); // TODO: check for errors - point_name = ""; + point_name.clear(); } - else if (stream.name().compare("trkseg", Qt::CaseInsensitive) == 0 || - stream.name().compare("rte", Qt::CaseInsensitive) == 0) + else if (stream.name().compare(QLatin1String("trkseg"), Qt::CaseInsensitive) == 0 + || stream.name().compare(QLatin1String("rte"), Qt::CaseInsensitive) == 0) { if (segment_starts.size() == 0 || segment_starts.back() < (int)segment_points.size()) @@ -378,26 +378,26 @@ bool Track::loadFromGPX(QFile* file, bool project_points, QWidget* dialog_parent segment_starts.push_back(segment_points.size()); } } - else if (stream.name().compare("ele", Qt::CaseInsensitive) == 0) + else if (stream.name().compare(QLatin1String("ele"), Qt::CaseInsensitive) == 0) point.elevation = stream.readElementText().toFloat(); - else if (stream.name().compare("time", Qt::CaseInsensitive) == 0) + else if (stream.name().compare(QLatin1String("time"), Qt::CaseInsensitive) == 0) point.datetime = QDateTime::fromString(stream.readElementText(), Qt::ISODate); - else if (stream.name().compare("sat", Qt::CaseInsensitive) == 0) + else if (stream.name().compare(QLatin1String("sat"), Qt::CaseInsensitive) == 0) point.num_satellites = stream.readElementText().toInt(); - else if (stream.name().compare("hdop", Qt::CaseInsensitive) == 0) + else if (stream.name().compare(QLatin1String("hdop"), Qt::CaseInsensitive) == 0) point.hDOP = stream.readElementText().toFloat(); - else if (stream.name().compare("name", Qt::CaseInsensitive) == 0) + else if (stream.name().compare(QLatin1String("name"), Qt::CaseInsensitive) == 0) point_name = stream.readElementText(); } else if (stream.tokenType() == QXmlStreamReader::EndElement) { - if (stream.name().compare("wpt", Qt::CaseInsensitive) == 0) + if (stream.name().compare(QLatin1String("wpt"), Qt::CaseInsensitive) == 0) { waypoints.push_back(point); waypoint_names.push_back(point_name); } - else if (stream.name().compare("trkpt", Qt::CaseInsensitive) == 0 || - stream.name().compare("rtept", Qt::CaseInsensitive) == 0) + else if (stream.name().compare(QLatin1String("trkpt"), Qt::CaseInsensitive) == 0 + || stream.name().compare(QLatin1String("rtept"), Qt::CaseInsensitive) == 0) { segment_points.push_back(point); } @@ -483,7 +483,7 @@ bool Track::loadFromDXF(QFile* file, bool project_points, QWidget* dialog_parent bool Track::loadFromOSM(QFile* file, bool project_points, QWidget* dialog_parent) { track_crs = new Georeferencing(); - track_crs->setProjectedCRS("", geographic_crs_spec); + track_crs->setProjectedCRS({}, geographic_crs_spec); track_crs->setTransformationDirectly(QTransform()); // Basic OSM file support @@ -496,7 +496,7 @@ bool Track::loadFromOSM(QFile* file, bool project_points, QWidget* dialog_parent QXmlStreamReader xml(file); if (xml.readNextStartElement()) { - if (xml.name() != "osm") + if (xml.name() != QLatin1String("osm")) { QMessageBox::critical(dialog_parent, TemplateTrack::tr("Error"), TemplateTrack::tr("%1:\nNot an OSM file.")); return false; @@ -504,15 +504,19 @@ bool Track::loadFromOSM(QFile* file, bool project_points, QWidget* dialog_parent else { QXmlStreamAttributes attributes(xml.attributes()); - const double osm_version = attributes.value("version").toString().toDouble(); + const double osm_version = attributes.value(QLatin1String("version")).toDouble(); if (osm_version < min_supported_version) { - QMessageBox::critical(dialog_parent, TemplateTrack::tr("Error"), TemplateTrack::tr("The OSM file has version %1.\nThe minimum supported version is %2.").arg(attributes.value("version").toString(), QString::number(min_supported_version, 'g', 1))); + QMessageBox::critical(dialog_parent, TemplateTrack::tr("Error"), + TemplateTrack::tr("The OSM file has version %1.\nThe minimum supported version is %2.").arg( + attributes.value(QLatin1String("version")).toString(), QString::number(min_supported_version, 'g', 1))); return false; } if (osm_version > max_supported_version) { - QMessageBox::critical(dialog_parent, TemplateTrack::tr("Error"), TemplateTrack::tr("The OSM file has version %1.\nThe maximum supported version is %2.").arg(attributes.value("version").toString(), QString::number(min_supported_version, 'g', 1))); + QMessageBox::critical(dialog_parent, TemplateTrack::tr("Error"), + TemplateTrack::tr("The OSM file has version %1.\nThe maximum supported version is %2.").arg( + attributes.value(QLatin1String("version")).toString(), QString::number(max_supported_version, 'g', 1))); return false; } } @@ -523,24 +527,24 @@ bool Track::loadFromOSM(QFile* file, bool project_points, QWidget* dialog_parent { const QStringRef name(xml.name()); QXmlStreamAttributes attributes(xml.attributes()); - if (attributes.value("visible") == "false") + if (attributes.value(QLatin1String("visible")) == QLatin1String("false")) { xml.skipCurrentElement(); continue; } - QString id(attributes.value("id").toString()); + QString id(attributes.value(QLatin1String("id")).toString()); if (id.isEmpty()) { - id = "!" + QString::number(++internal_node_id); + id = QLatin1Char('!') + QString::number(++internal_node_id); } - if (name == "node") + if (name == QLatin1String("node")) { bool ok = true; double lat = 0.0, lon = 0.0; - if (ok) lat = attributes.value("lat").toString().toDouble(&ok); - if (ok) lon = attributes.value("lon").toString().toDouble(&ok); + if (ok) lat = attributes.value(QLatin1String("lat")).toDouble(&ok); + if (ok) lon = attributes.value(QLatin1String("lon")).toDouble(&ok); if (!ok) { node_problems++; @@ -557,19 +561,19 @@ bool Track::loadFromOSM(QFile* file, bool project_points, QWidget* dialog_parent while (xml.readNextStartElement()) { - if (xml.name() == "tag") + if (xml.name() == QLatin1String("tag")) { - const QString k(xml.attributes().value("k").toString()); - const QString v(xml.attributes().value("v").toString()); + const QString k(xml.attributes().value(QLatin1String("k")).toString()); + const QString v(xml.attributes().value(QLatin1String("v")).toString()); element_tags[id][k] = v; - if (k == "ele") + if (k == QLatin1String("ele")) { bool ok; double elevation = v.toDouble(&ok); if (ok) nodes[id].elevation = elevation; } - else if (k == "name") + else if (k == QLatin1String("name")) { if (!v.isEmpty() && !nodes.contains(v)) { @@ -581,24 +585,24 @@ bool Track::loadFromOSM(QFile* file, bool project_points, QWidget* dialog_parent xml.skipCurrentElement(); } } - else if (name == "way") + else if (name == QLatin1String("way")) { segment_starts.push_back(segment_points.size()); segment_names.push_back(id); while (xml.readNextStartElement()) { - if (xml.name() == "nd") + if (xml.name() == QLatin1String("nd")) { - QString ref = xml.attributes().value("ref").toString(); + QString ref = xml.attributes().value(QLatin1String("ref")).toString(); if (ref.isEmpty() || !nodes.contains(ref)) node_problems++; else segment_points.push_back(nodes[ref]); } - else if (xml.name() == "tag") + else if (xml.name() == QLatin1String("tag")) { - const QString k(xml.attributes().value("k").toString()); - const QString v(xml.attributes().value("v").toString()); + const QString k(xml.attributes().value(QLatin1String("k")).toString()); + const QString v(xml.attributes().value(QLatin1String("v")).toString()); element_tags[id][k] = v; } xml.skipCurrentElement(); diff --git a/src/gui/about_dialog.cpp b/src/gui/about_dialog.cpp index bd7b06243..00786d19e 100644 --- a/src/gui/about_dialog.cpp +++ b/src/gui/about_dialog.cpp @@ -35,7 +35,7 @@ * But an empty URL will be ignored by QTextBrowser's history, leading to * unexpected behaviour of backward navigation. */ -const QUrl about_page_url = QUrl(QStringLiteral("#ABOUT")); +const QUrl about_page_url = QUrl(QString::fromLatin1("#ABOUT")); /** * Puts the items of a QStringList into an HTML block or a sequence of blocks. @@ -43,38 +43,39 @@ const QUrl about_page_url = QUrl(QStringLiteral("#ABOUT")); static QString formatBlock(const QStringList& items) { #if defined(Q_OS_ANDROID) // or any other small-screen device - QString block = QStringLiteral("

"); - block.append(items.join(QStringLiteral(", "))); - block.append(QStringLiteral("

")); - return block; + QString block = QLatin1String("

") + + items.join(QString::fromLatin1(", ")) + + QLatin1String("

"); #else - const int columns = 3; + QString block; + block.reserve(100 + 30 * items.size()); + block.append(QLatin1String("
")); + constexpr int columns = 3; const int rows = (int)ceil((double)items.size() / columns); - QString table(QStringLiteral("
")); - for(int i = 0, row = 1; i < items.size(); ++i) + for (int i = 0, row = 1; i < items.size(); ++i) { - table.append(items[i]); + block.append(items[i]); if (rows != row) { - table.append(QStringLiteral("
")); + block.append(QString::fromLatin1("
")); ++row; } else if (i < items.size()) { - table.append(QStringLiteral("
   ")); + block.append(QString::fromLatin1("   ")); row = 1; } } - table.append(QStringLiteral("
")); - return table; + block.append(QString::fromLatin1("
")); #endif + return block; } AboutDialog::AboutDialog(QWidget* parent) : TextBrowserDialog(about_page_url, parent) { - text_browser->setSearchPaths(text_browser->searchPaths() << QStringLiteral(":/doc/licensing/html/")); + text_browser->setSearchPaths(text_browser->searchPaths() << QString::fromLatin1(":/doc/licensing/html/")); text_browser->setHtml(about()); text_browser->document()->adjustSize(); updateWindowTitle(); @@ -97,90 +98,79 @@ void AboutDialog::updateWindowTitle() QString AboutDialog::about() { static QStringList developers_list( QStringList() - << QStringLiteral("Peter Curtis (2012-2013)") - << QStringLiteral("Kai Pastor") - << QStringLiteral("Thomas Schöps (2012-2014, %1)") + << QString::fromLatin1("Peter Curtis (2012-2013)") + << QString::fromLatin1("Kai Pastor") + << QString::fromUtf8("Thomas Schöps (2012-2014, %1)") ); static QStringList contributors_list( QStringList() - << QStringLiteral("Javier Arufe") - << QStringLiteral("Jon Cundill") - << QStringLiteral("Sławomir Cygler") - << QStringLiteral("Jan Dalheimer") - << QStringLiteral("Davide De Nardis") - << QStringLiteral("Eugeniy Fedirets") - << QStringLiteral("Pavel Fric") - << QStringLiteral("Anders Gressli") - << QStringLiteral("Peter Hoban") - << QStringLiteral("Henrik Johansson") - << QStringLiteral("Panu Karhu") - << QStringLiteral("Oskar Karlin") - << QStringLiteral("Matthias Kühlewein") - << QStringLiteral("Albin Larsson") - << QStringLiteral("István Marczis") - << QStringLiteral("Tojo Masaya") - << QStringLiteral("Yevhen Mazur") - << QStringLiteral("Fraser Mills") - << QStringLiteral("Vincent Poinsignon") - << QStringLiteral("Russell Porter") - << QStringLiteral("Christopher Schive") - << QStringLiteral("Semyon Yakimov") - << QStringLiteral("Aivars Zogla") + << QString::fromLatin1("Javier Arufe") + << QString::fromLatin1("Eric Boulet") + << QString::fromLatin1("Jon Cundill") + << QString::fromUtf8("Sławomir Cygler") + << QString::fromLatin1("Jan Dalheimer") + << QString::fromLatin1("Davide De Nardis") + << QString::fromLatin1("Eugeniy Fedirets") + << QString::fromLatin1("Pavel Fric") + << QString::fromLatin1("Anders Gressli") + << QString::fromLatin1("Peter Hoban") + << QString::fromLatin1("Henrik Johansson") + << QString::fromLatin1("Panu Karhu") + << QString::fromLatin1("Oskar Karlin") + << QString::fromUtf8("Matthias Kühlewein") + << QString::fromLatin1("Albin Larsson") + << QString::fromUtf8("István Marczis") + << QString::fromLatin1("Tojo Masaya") + << QString::fromLatin1("Yevhen Mazur") + << QString::fromLatin1("Fraser Mills") + << QString::fromLatin1("Vincent Poinsignon") + << QString::fromLatin1("Russell Porter") + << QString::fromLatin1("Christopher Schive") + << QString::fromLatin1("Semyon Yakimov") + << QString::fromLatin1("Aivars Zogla") ); - QString mapper_about( - QString("" - "%0" - "" - "" - "" - "" - "
" - "

%1 %2

" - "

" - "%3
" - "%4

" - "

Copyright (C) 2015 The OpenOrienteering developers

" - "

%5

" - "

%6

" - "

%7

" - "

%8

%9" - "

 
%10

%11" - "" - ). - // %0 - arg(tr("About %1")). - // %1 %2 - arg(APP_NAME).arg(APP_VERSION). - // %3 - arg(tr("A free software for drawing orienteering maps")). - // %4 - arg("http://openorienteering.org/apps/mapper/"). - // %5 - arg(tr("This program is free software: you can redistribute it " - "and/or modify it under the terms of the " - "GNU General Public License (GPL), version 3, " - "as published by the Free Software Foundation."). - arg("href=\"gpl-3-0.html\"")). + QString mapper_about = QString::fromLatin1( + "" + "%0" + "" + "" + "" + "" + "
" + "

%1

" + "

" + "%3
" + "%4

" + "

Copyright (C) 2016 The OpenOrienteering developers

" + "

%5

" + "

%6

" + "

%7

" + "

%8

%9" + "

 
%10

%11" + "" + ).arg( + tr("About %1").arg(APP_NAME), // %0 + qApp->applicationDisplayName(), // %1 + tr("A free software for drawing orienteering maps"), // %3 + QString::fromLatin1("http://openorienteering.org/apps/mapper/"), // %4 + tr("This program is free software: you can redistribute it " + "and/or modify it under the terms of the " + "GNU General Public License (GPL), version 3, " + "as published by the Free Software Foundation.").arg(QString::fromLatin1("href=\"gpl-3-0.html\"")), // %5 // %6 - arg(tr("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 (GPL), version 3, for " - "more details."). - arg("href=\"gpl-3-0.html#15-disclaimer-of-warranty\"")). - // %7 - arg(tr("All about licenses, copyright notices, conditions and " - "disclaimers."). - arg(QStringLiteral("href=\"licensing.html\""))). - // %8 - arg(tr("The OpenOrienteering developers in alphabetical order:")). - // %9 - arg(formatBlock(developers_list).arg(tr("(project initiator)").replace('(',QString::null).replace(')',QString::null))). - // %10 - arg(tr("For contributions, thanks to:")). - // %11 - arg(formatBlock(contributors_list)) ); + tr("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 (GPL), version 3, for " + "more details.").arg(QString::fromLatin1("href=\"gpl-3-0.html#15-disclaimer-of-warranty\"")), // %6 + tr("All about licenses, copyright notices, conditions and disclaimers.").arg(QString::fromLatin1("href=\"licensing.html\"")) // %7 + ).arg( + tr("The OpenOrienteering developers in alphabetical order:"), // %8 + formatBlock(developers_list).arg(tr("(project initiator)").replace(QLatin1Char('('), QString{}).replace(QLatin1Char(')'), QString{})), // %9 + tr("For contributions, thanks to:"), // %10 + formatBlock(contributors_list) // %11 + ); return mapper_about; } diff --git a/src/gui/autosave_dialog.cpp b/src/gui/autosave_dialog.cpp index 1a01750fe..5cf824791 100644 --- a/src/gui/autosave_dialog.cpp +++ b/src/gui/autosave_dialog.cpp @@ -36,7 +36,7 @@ AutosaveDialog::AutosaveDialog(QString path, QString autosave_path, QString actu , autosave_path(autosave_path) , resolved(false) { - const QString text_template = QString("%1
%2
%3"); + const QString text_template = QString::fromLatin1("%1
%2
%3"); QFileInfo autosaved_file_info(autosave_path); autosaved_text.setHtml(text_template. @@ -56,7 +56,7 @@ AutosaveDialog::AutosaveDialog(QString path, QString autosave_path, QString actu setWindowTitle(tr("File recovery")); QString intro_text = tr("File %1 was not properly closed. At the moment, there are two versions:"); - QLabel* label = new QLabel(intro_text.arg(QString("%1").arg(user_saved_file_info.fileName()))); + QLabel* label = new QLabel(intro_text.arg(QString::fromLatin1("%1").arg(user_saved_file_info.fileName()))); label->setWordWrap(true); layout->addWidget(label); diff --git a/src/gui/color_dialog.cpp b/src/gui/color_dialog.cpp index e76059653..95c73263c 100644 --- a/src/gui/color_dialog.cpp +++ b/src/gui/color_dialog.cpp @@ -149,7 +149,7 @@ ColorDialog::ColorDialog(const Map& map, const MapColor& source_color, QWidget* QWidget* prof_color_widget = new QWidget(); prof_color_widget->setLayout(prof_color_layout); - prof_color_widget->setObjectName("professional"); + prof_color_widget->setObjectName(QString::fromLatin1("professional")); QGridLayout* desktop_layout = new QGridLayout(); @@ -178,17 +178,17 @@ ColorDialog::ColorDialog(const Map& map, const MapColor& source_color, QWidget* desktop_layout->addWidget(custom_rgb_option, row, col, 1, 2); ++row; - r_edit = Util::SpinBox::create(1, 0.0, 255.0, "", 5); + r_edit = Util::SpinBox::create(1, 0.0, 255.0, {}, 5); desktop_layout->addWidget(new QLabel(tr("Red")), row, col); desktop_layout->addWidget(r_edit, row, col+1); ++row; - g_edit = Util::SpinBox::create(1, 0.0, 255.0, "", 5); + g_edit = Util::SpinBox::create(1, 0.0, 255.0, {}, 5); desktop_layout->addWidget(new QLabel(tr("Green")), row, col); desktop_layout->addWidget(g_edit, row, col+1); ++row; - b_edit = Util::SpinBox::create(1, 0.0, 255.0, "", 5); + b_edit = Util::SpinBox::create(1, 0.0, 255.0, {}, 5); desktop_layout->addWidget(new QLabel(tr("Blue")), row, col); desktop_layout->addWidget(b_edit, row, col+1); @@ -208,7 +208,7 @@ ColorDialog::ColorDialog(const Map& map, const MapColor& source_color, QWidget* QWidget* desktop_color_widget = new QWidget(); desktop_color_widget->setLayout(desktop_layout); - desktop_color_widget->setObjectName("desktop"); + desktop_color_widget->setObjectName(QString::fromLatin1("desktop")); properties_widget = new QTabWidget(); @@ -257,8 +257,8 @@ ColorDialog::ColorDialog(const Map& map, const MapColor& source_color, QWidget* connect(b_edit, SIGNAL(valueChanged(double)), this, SLOT(rgbValueChanged())); QSettings settings; - settings.beginGroup("ColorDialog"); - QString default_view = settings.value("view").toString(); + settings.beginGroup(QString::fromLatin1("ColorDialog")); + QString default_view = settings.value(QString::fromLatin1("view")).toString(); settings.endGroup(); properties_widget->setCurrentWidget(properties_widget->findChild(default_view)); } @@ -433,8 +433,8 @@ void ColorDialog::updateWidgets() void ColorDialog::accept() { QSettings settings; - settings.beginGroup("ColorDialog"); - settings.setValue("view", properties_widget->currentWidget()->objectName()); + settings.beginGroup(QString::fromLatin1("ColorDialog")); + settings.setValue(QString::fromLatin1("view"), properties_widget->currentWidget()->objectName()); settings.endGroup(); QDialog::accept(); @@ -489,7 +489,7 @@ void ColorDialog::spotColorTypeChanged(int id) case MapColor::SpotColor: name = color.getName(); if (name.isEmpty()) - name = "?"; + name = QLatin1Char('?'); color.setSpotColorName(name); break; case MapColor::CustomColor: diff --git a/src/gui/configure_grid_dialog.cpp b/src/gui/configure_grid_dialog.cpp index 14c225155..d19b8ae10 100644 --- a/src/gui/configure_grid_dialog.cpp +++ b/src/gui/configure_grid_dialog.cpp @@ -45,10 +45,10 @@ ConfigureGridDialog::ConfigureGridDialog(QWidget* parent, const Map& map, bool grid_visible) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint) , map(map) -, grid{ map.getGrid() } -, grid_visible{ grid_visible } -, current_color{ grid.getColor() } -, current_unit{ grid.getUnit() } +, grid(map.getGrid()) +, grid_visible(grid_visible) +, current_color(grid.getColor()) +, current_unit(grid.getUnit()) { setWindowTitle(tr("Configure grid")); @@ -240,7 +240,7 @@ void ConfigureGridDialog::updateStates() unit_combo->setEnabled(show_grid_check->isChecked()); - QString unit_suffix = QString(" ") % ((current_unit == MapGrid::MetersInTerrain) ? tr("m", "meters") : tr("mm", "millimeters")); + QString unit_suffix = QLatin1Char(' ') + ((current_unit == MapGrid::MetersInTerrain) ? tr("m", "meters") : tr("mm", "millimeters")); horz_spacing_edit->setEnabled(show_grid_check->isChecked() && display_mode != MapGrid::HorizontalLines); horz_spacing_edit->setSuffix(unit_suffix); vert_spacing_edit->setEnabled(show_grid_check->isChecked() && display_mode != MapGrid::VerticalLines); diff --git a/src/gui/georeferencing_dialog.cpp b/src/gui/georeferencing_dialog.cpp index 5eed6eaaa..9d8139db6 100644 --- a/src/gui/georeferencing_dialog.cpp +++ b/src/gui/georeferencing_dialog.cpp @@ -98,6 +98,12 @@ GeoreferencingDialog::GeoreferencingDialog( status_label = new QLabel(tr("Status:")); status_field = new QLabel(); + /*: The grid scale factor is the ratio between a length in the grid plane + and the corresponding length on the curved earth model. It is applied + as a factor to ground distances to get grid plane distances. */ + auto scale_factor_label = new QLabel(tr("Grid scale factor:")); + scale_factor_edit = Util::SpinBox::create(Georeferencing::scaleFactorPrecision(), 0.001, 1000.0); + QLabel* reference_point_label = Util::Headline::create(tr("Reference point")); ref_point_button = new QPushButton(tr("&Pick on map")); @@ -157,7 +163,7 @@ GeoreferencingDialog::GeoreferencingDialog( QLabel* map_north_label = Util::Headline::create(tr("Map north")); declination_edit = Util::SpinBox::create(Georeferencing::declinationPrecision(), -180.0, +180.0, trUtf8("°")); - declination_button = new QPushButton(""); + declination_button = new QPushButton(tr("Lookup...")); QHBoxLayout* declination_layout = new QHBoxLayout(); declination_layout->addWidget(declination_edit, 1); #if defined(QT_NETWORK_LIB) @@ -181,6 +187,7 @@ GeoreferencingDialog::GeoreferencingDialog( edit_layout->addRow(tr("&Coordinate reference system:"), crs_selector); crs_selector->setDialogLayout(edit_layout); edit_layout->addRow(status_label, status_field); + edit_layout->addRow(scale_factor_label, scale_factor_edit); edit_layout->addItem(Util::SpacerItem::create(this)); edit_layout->addRow(reference_point_label); @@ -190,7 +197,7 @@ GeoreferencingDialog::GeoreferencingDialog( edit_layout->addRow(show_refpoint_label, link_label); edit_layout->addRow(show_refpoint_label, link_label); edit_layout->addRow(tr("On CRS changes, keep:"), keep_projected_radio); - edit_layout->addRow("", keep_geographic_radio); + edit_layout->addRow({}, keep_geographic_radio); edit_layout->addItem(Util::SpacerItem::create(this)); edit_layout->addRow(map_north_label); @@ -208,6 +215,8 @@ GeoreferencingDialog::GeoreferencingDialog( connect(crs_selector, &CRSSelector::crsChanged, this, &GeoreferencingDialog::crsEdited); using TakingDoubleArgument = void (QDoubleSpinBox::*)(double); + connect(scale_factor_edit, (TakingDoubleArgument)&QDoubleSpinBox::valueChanged, this, &GeoreferencingDialog::scaleFactorEdited); + connect(map_x_edit, (TakingDoubleArgument)&QDoubleSpinBox::valueChanged, this, &GeoreferencingDialog::mapRefChanged); connect(map_y_edit, (TakingDoubleArgument)&QDoubleSpinBox::valueChanged, this, &GeoreferencingDialog::mapRefChanged); connect(ref_point_button, &QPushButton::clicked, this, &GeoreferencingDialog::selectMapRefPoint); @@ -271,7 +280,8 @@ void GeoreferencingDialog::transformationChanged() { ScopedMultiSignalsBlocker block( map_x_edit, map_y_edit, - easting_edit, northing_edit + easting_edit, northing_edit, + scale_factor_edit ); map_x_edit->setValue(georef->getMapRefPoint().x()); @@ -280,6 +290,8 @@ void GeoreferencingDialog::transformationChanged() easting_edit->setValue(georef->getProjectedRefPoint().x()); northing_edit->setValue(georef->getProjectedRefPoint().y()); + scale_factor_edit->setValue(georef->getGridScaleFactor()); + updateGrivation(); } @@ -299,7 +311,7 @@ void GeoreferencingDialog::projectionChanged() { // The CRS id is not there anymore or the number of parameters has changed. // Enter as custom spec. - crs_selector->setCurrentCRS(CRSTemplateRegistry().find("PROJ.4"), { georef->getProjectedCRSSpec() }); + crs_selector->setCurrentCRS(CRSTemplateRegistry().find(QString::fromLatin1("PROJ.4")), { georef->getProjectedCRSSpec() }); } else { @@ -313,10 +325,10 @@ void GeoreferencingDialog::projectionChanged() lat_edit->setValue(latitude); lon_edit->setValue(longitude); QString osm_link = - QString("http://www.openstreetmap.org/?lat=%1&lon=%2&zoom=18&layers=M"). + QString::fromLatin1("http://www.openstreetmap.org/?lat=%1&lon=%2&zoom=18&layers=M"). arg(latitude).arg(longitude); QString worldofo_link = - QString("http://maps.worldofo.com/?zoom=15&lat=%1&lng=%2"). + QString::fromLatin1("http://maps.worldofo.com/?zoom=15&lat=%1&lng=%2"). arg(latitude).arg(longitude); link_label->setText( tr("OpenStreetMap | World of O Maps"). @@ -328,7 +340,7 @@ void GeoreferencingDialog::projectionChanged() if (error.length() == 0) status_field->setText(tr("valid")); else - status_field->setText(QString("") % error % ""); + status_field->setText(QLatin1String("") + error + QLatin1String("")); } // slot @@ -345,8 +357,8 @@ void GeoreferencingDialog::requestDeclination(bool no_confirm) return; // TODO: Move to resources or preferences. Assess security risks of url distinction. - QString user_url("http://www.ngdc.noaa.gov/geomag-web/"); - QUrl service_url("http://www.ngdc.noaa.gov/geomag-web/calculators/calculateDeclination"); + QString user_url(QString::fromLatin1("http://www.ngdc.noaa.gov/geomag-web/")); + QUrl service_url(QString::fromLatin1("http://www.ngdc.noaa.gov/geomag-web/calculators/calculateDeclination")); LatLon latlon(georef->getGeographicRefPoint()); if (!no_confirm) @@ -368,12 +380,12 @@ void GeoreferencingDialog::requestDeclination(bool no_confirm) QUrlQuery query; QDate today = QDate::currentDate(); - query.addQueryItem("lat1", QString::number(latlon.latitude())); - query.addQueryItem("lon1", QString::number(latlon.longitude())); - query.addQueryItem("startYear", QString::number(today.year())); - query.addQueryItem("startMonth", QString::number(today.month())); - query.addQueryItem("startDay", QString::number(today.day())); - query.addQueryItem("resultFormat", "xml"); + query.addQueryItem(QString::fromLatin1("lat1"), QString::number(latlon.latitude())); + query.addQueryItem(QString::fromLatin1("lon1"), QString::number(latlon.longitude())); + query.addQueryItem(QString::fromLatin1("startYear"), QString::number(today.year())); + query.addQueryItem(QString::fromLatin1("startMonth"), QString::number(today.month())); + query.addQueryItem(QString::fromLatin1("startDay"), QString::number(today.day())); + query.addQueryItem(QString::fromLatin1("resultFormat"), QString::fromLatin1("xml")); service_url.setQuery(query); network->get(QNetworkRequest(service_url)); #else @@ -453,7 +465,7 @@ void GeoreferencingDialog::updateWidgets() ref_point_button->setEnabled(controller != nullptr); if (crs_selector->currentCRSTemplate()) - projected_ref_label->setText(crs_selector->currentCRSTemplate()->coordinatesName(crs_selector->parameters()) + ":"); + projected_ref_label->setText(crs_selector->currentCRSTemplate()->coordinatesName(crs_selector->parameters()) + QLatin1Char(':')); else projected_ref_label->setText(tr("Local coordinates:")); @@ -489,7 +501,7 @@ void GeoreferencingDialog::updateGrivation() { QString text = trUtf8("%1 °", "degree value").arg(QLocale().toString(georef->getGrivation(), 'f', Georeferencing::declinationPrecision())); if (grivation_locked) - text.append(QString(" (%1)").arg(tr("locked"))); + text.append(QString::fromLatin1(" (%1)").arg(tr("locked"))); grivation_label->setText(text); } @@ -527,6 +539,13 @@ void GeoreferencingDialog::crsEdited() reset_button->setEnabled(true); } +void GeoreferencingDialog::scaleFactorEdited() +{ + const QSignalBlocker block{scale_factor_edit}; + georef->setGridScaleFactor(scale_factor_edit->value()); + reset_button->setEnabled(true); +} + void GeoreferencingDialog::selectMapRefPoint() { if (controller) @@ -602,15 +621,15 @@ void GeoreferencingDialog::declinationReplyFinished(QNetworkReply* reply) QXmlStreamReader xml(reply); while (xml.readNextStartElement()) { - if (xml.name() == "maggridresult") + if (xml.name() == QLatin1String("maggridresult")) { while(xml.readNextStartElement()) { - if (xml.name() == "result") + if (xml.name() == QLatin1String("result")) { while (xml.readNextStartElement()) { - if (xml.name() == "declination") + if (xml.name() == QLatin1String("declination")) { QString text = xml.readElementText(QXmlStreamReader::IncludeChildElements); bool ok; @@ -622,7 +641,7 @@ void GeoreferencingDialog::declinationReplyFinished(QNetworkReply* reply) } else { - error_string = tr("Could not parse data.") % ' '; + error_string = tr("Could not parse data.") + QLatin1Char(' '); } } @@ -633,9 +652,9 @@ void GeoreferencingDialog::declinationReplyFinished(QNetworkReply* reply) xml.skipCurrentElement(); // child of mapgridresult } } - else if (xml.name() == "errors") + else if (xml.name() == QLatin1String("errors")) { - error_string.append(xml.readElementText(QXmlStreamReader::IncludeChildElements) % ' '); + error_string.append(xml.readElementText(QXmlStreamReader::IncludeChildElements) + QLatin1Char(' ')); } xml.skipCurrentElement(); // child of root @@ -721,6 +740,6 @@ bool GeoreferencingTool::mouseReleaseEvent(QMouseEvent* event, MapCoordF map_coo const QCursor& GeoreferencingTool::getCursor() const { - static auto const cursor = QCursor(QPixmap(":/images/cursor-crosshair.png"), 11, 11); + static auto const cursor = scaledToScreen(QCursor{ QPixmap{ QString::fromLatin1(":/images/cursor-crosshair.png") }, 11, 11 }); return cursor; } diff --git a/src/gui/georeferencing_dialog.h b/src/gui/georeferencing_dialog.h index e36ddf6db..4992038ed 100644 --- a/src/gui/georeferencing_dialog.h +++ b/src/gui/georeferencing_dialog.h @@ -188,6 +188,11 @@ Q_OBJECT */ void crsEdited(); + /** + * Notifies the dialog of a change in the grid scale factor. + */ + void scaleFactorEdited(); + /** * Hides the dialog and activates a GeoreferencingTool for selecting * the reference point on the map. @@ -245,6 +250,7 @@ Q_OBJECT CRSSelector* crs_selector; QLabel* status_label; QLabel* status_field; + QDoubleSpinBox* scale_factor_edit; QDoubleSpinBox* map_x_edit; QDoubleSpinBox* map_y_edit; diff --git a/src/gui/home_screen_controller.cpp b/src/gui/home_screen_controller.cpp index a2c84f554..954825fb1 100644 --- a/src/gui/home_screen_controller.cpp +++ b/src/gui/home_screen_controller.cpp @@ -44,7 +44,7 @@ void HomeScreenController::attach(MainWindow* window) { this->window = window; - if (window->mobileMode()) + if (MainWindow::mobileMode()) { widget = new HomeScreenWidgetMobile(this); } @@ -52,7 +52,7 @@ void HomeScreenController::attach(MainWindow* window) { widget = new HomeScreenWidgetDesktop(this); window->statusBar()->hide(); - window->setStatusBarText(""); + window->setStatusBarText(QString{}); } window->setCentralWidget(widget); @@ -64,7 +64,7 @@ void HomeScreenController::attach(MainWindow* window) void HomeScreenController::detach() { - if (!window->mobileMode()) + if (!MainWindow::mobileMode()) { window->statusBar()->show(); } @@ -126,13 +126,13 @@ void HomeScreenController::goToTip(int index) if (tips.isEmpty()) { // Normally, this will be read only once. - QFile file(":/help/tip-of-the-day/tips.txt"); + QFile file(QString::fromLatin1(":/help/tip-of-the-day/tips.txt")); if (file.open(QIODevice::ReadOnly)) { while (!file.atEnd()) { QString tip(QString::fromUtf8(file.readLine().constData())); - if (tip.endsWith('\n')) + if (tip.endsWith(QLatin1Char('\n'))) tip.chop(1); if (!tip.isEmpty()) tips.push_back(tip); @@ -144,7 +144,7 @@ void HomeScreenController::goToTip(int index) { // Some error may have occured during reading the tips file. // Display a welcome text. - widget->setTipOfTheDay(QString("

%1

").arg(tr("Welcome to OpenOrienteering Mapper!"))); + widget->setTipOfTheDay(QString::fromLatin1("

%1

").arg(tr("Welcome to OpenOrienteering Mapper!"))); } else { diff --git a/src/gui/main_window.cpp b/src/gui/main_window.cpp index 3502d4b05..00f4bb4bf 100644 --- a/src/gui/main_window.cpp +++ b/src/gui/main_window.cpp @@ -1,6 +1,6 @@ /* * Copyright 2012, 2013, 2014 Thomas Schöps - * Copyright 2012-2015 Kai Pastor + * Copyright 2012-2016 Kai Pastor * * This file is part of OpenOrienteering. * @@ -30,74 +30,62 @@ #include #include #include -#include #include #include #include -#include #include #include +#if defined(Q_OS_ANDROID) +# include +#endif + #include #include "about_dialog.h" #include "autosave_dialog.h" +#include "home_screen_controller.h" +#include "settings_dialog.h" +#include "text_browser_dialog.h" #include "../file_format_registry.h" #include "../file_import_export.h" -#include "home_screen_controller.h" #include "../map.h" #include "../map_dialog_new.h" #include "../map_editor.h" #include "../mapper_resource.h" #include "../file_format.h" #include "../settings.h" -#include "settings_dialog.h" -#include "text_browser_dialog.h" +#include "../symbol.h" +#include "../undo_manager.h" #include "../util.h" - -#if defined(Q_OS_ANDROID) -#include -#endif +#include "../util/backports.h" +constexpr int MainWindow::max_recent_files; int MainWindow::num_open_files = 0; -MainWindow::MainWindow(bool as_main_window) -: QMainWindow() -, has_autosave_conflict(false) -, homescreen_disabled(false) +MainWindow::MainWindow(QWidget* parent, Qt::WindowFlags flags) +: MainWindow { true, parent, flags } { -#if (defined Q_OS_MAC) - // Cf. qtbase/src/plugins/platforms/cocoa/qcocoamenuloader.mm. - // These translations should come with Qt, but were missing - // for some languages (at least for de in Qt 5.0.1). - static const char *application_menu_strings[] = { - QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU", "Services"), - QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU", "Hide %1"), - QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU", "Hide Others"), - QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU", "Show All"), - QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU", "Preferences..."), - QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU", "Quit %1"), - QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU", "About %1") - }; - Q_UNUSED(application_menu_strings) -#endif - - controller = NULL; - has_unsaved_changes = false; - has_opened_file = false; + // nothing else +} - create_menu = as_main_window; - show_menu = create_menu && !mobileMode(); - - disable_shortcuts = false; - setCurrentPath(QString()); - maximized_before_fullscreen = false; - general_toolbar = NULL; - file_menu = NULL; - - setWindowIcon(QIcon(":/images/mapper.png")); +MainWindow::MainWindow(bool as_main_window, QWidget* parent, Qt::WindowFlags flags) +: QMainWindow { parent, flags } +, controller { nullptr } +, create_menu { as_main_window } +, show_menu { create_menu && !mobileMode() } +, shortcuts_blocked { false } +, general_toolbar { nullptr } +, file_menu { nullptr } +, has_opened_file { false } +, has_unsaved_changes { false } +, has_autosave_conflict { false } +, maximized_before_fullscreen { false } +, homescreen_disabled { false } +{ + setWindowIcon(QIcon(QString::fromLatin1(":/images/mapper.png"))); setAttribute(Qt::WA_DeleteOnClose); status_label = new QLabel(); @@ -119,7 +107,7 @@ MainWindow::MainWindow(bool as_main_window) installEventFilter(this); #endif - connect(&Settings::getInstance(), SIGNAL(settingsChanged()), this, SLOT(settingsChanged())); + connect(&Settings::getInstance(), &Settings::settingsChanged, this, &MainWindow::settingsChanged); } MainWindow::~MainWindow() @@ -137,29 +125,24 @@ void MainWindow::settingsChanged() updateRecentFileActions(); } -const QString& MainWindow::appName() const +QString MainWindow::appName() const { - static QString app_name(APP_NAME); - return app_name; + return APP_NAME; } -bool MainWindow::mobileMode() const +#ifndef Q_OS_ANDROID +bool MainWindow::mobileMode() { -#ifdef Q_OS_ANDROID - static bool mobile_mode = qEnvironmentVariableIsSet("MAPPER_MOBILE_GUI") - ? (qgetenv("MAPPER_MOBILE_GUI") != "0") - : 1; -#else static bool mobile_mode = qEnvironmentVariableIsSet("MAPPER_MOBILE_GUI") ? (qgetenv("MAPPER_MOBILE_GUI") != "0") : 0; -#endif return mobile_mode; } +#endif void MainWindow::setCentralWidget(QWidget* widget) { - if (widget != NULL) + if (widget) { // Main window shall not resize to central widget size hint. widget->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); @@ -181,24 +164,34 @@ void MainWindow::setHomeScreenDisabled(bool disabled) homescreen_disabled = disabled; } +void MainWindow::setController(MainWindowController* new_controller) +{ + setController(new_controller, false); + setCurrentPath({}); +} + void MainWindow::setController(MainWindowController* new_controller, const QString& path) +{ + setController(new_controller, true); + setCurrentPath(path); +} + +void MainWindow::setController(MainWindowController* new_controller, bool has_file) { if (controller) { controller->detach(); delete controller; - controller = NULL; + controller = nullptr; if (show_menu) menuBar()->clear(); delete general_toolbar; - general_toolbar = NULL; + general_toolbar = nullptr; } - has_opened_file = false; - has_unsaved_changes = false; - disable_shortcuts = false; - setCurrentPath(path); + has_opened_file = has_file; + shortcuts_blocked = false; if (create_menu) createFileMenu(); @@ -208,7 +201,7 @@ void MainWindow::setController(MainWindowController* new_controller, const QStri if (create_menu) createHelpMenu(); - + #if defined(Q_OS_MAC) if (isVisible() && qApp->activeWindow() == this) { @@ -218,77 +211,78 @@ void MainWindow::setController(MainWindowController* new_controller, const QStri qApp->focusWindowChanged(qApp->focusWindow()); } #endif + + setHasAutosaveConflict(false); + setHasUnsavedChanges(false); } void MainWindow::createFileMenu() { - QAction* new_act = new QAction(QIcon(":/images/new.png"), tr("&New"), this); + QAction* new_act = new QAction(QIcon(QString::fromLatin1(":/images/new.png")), tr("&New"), this); new_act->setShortcuts(QKeySequence::New); new_act->setStatusTip(tr("Create a new map")); - new_act->setWhatsThis("See more"); - connect(new_act, SIGNAL(triggered()), this, SLOT(showNewMapWizard())); + new_act->setWhatsThis(Util::makeWhatThis("file_menu.html")); + connect(new_act, &QAction::triggered, this, &MainWindow::showNewMapWizard); - QAction* open_act = new QAction(QIcon(":/images/open.png"), tr("&Open..."), this); + QAction* open_act = new QAction(QIcon(QString::fromLatin1(":/images/open.png")), tr("&Open..."), this); open_act->setShortcuts(QKeySequence::Open); open_act->setStatusTip(tr("Open an existing file")); - open_act->setWhatsThis("See more"); - connect(open_act, SIGNAL(triggered()), this, SLOT(showOpenDialog())); + open_act->setWhatsThis(Util::makeWhatThis("file_menu.html")); + connect(open_act, &QAction::triggered, this, &MainWindow::showOpenDialog); open_recent_menu = new QMenu(tr("Open &recent"), this); - open_recent_menu->setWhatsThis("See more"); + open_recent_menu->setWhatsThis(Util::makeWhatThis("file_menu.html")); for (int i = 0; i < max_recent_files; ++i) { recent_file_act[i] = new QAction(this); - connect(recent_file_act[i], SIGNAL(triggered()), this, SLOT(openRecentFile())); + connect(recent_file_act[i], &QAction::triggered, this, &MainWindow::openRecentFile); } open_recent_menu_inserted = false; // NOTE: if you insert something between open_recent_menu and save_act, adjust updateRecentFileActions()! - save_act = new QAction(QIcon(":/images/save.png"), tr("&Save"), this); + save_act = new QAction(QIcon(QString::fromLatin1(":/images/save.png")), tr("&Save"), this); save_act->setShortcuts(QKeySequence::Save); - save_act->setWhatsThis("See more"); - connect(save_act, SIGNAL(triggered()), this, SLOT(save())); + save_act->setWhatsThis(Util::makeWhatThis("file_menu.html")); + connect(save_act, &QAction::triggered, this, &MainWindow::save); - save_as_act = new QAction(tr("Save &as..."), this); + auto save_as_act = new QAction(tr("Save &as..."), this); if (QKeySequence::keyBindings(QKeySequence::SaveAs).empty()) save_as_act->setShortcut(tr("Ctrl+Shift+S")); else save_as_act->setShortcuts(QKeySequence::SaveAs); - save_as_act->setWhatsThis("See more"); - connect(save_as_act, SIGNAL(triggered()), this, SLOT(showSaveAsDialog())); + save_as_act->setWhatsThis(Util::makeWhatThis("file_menu.html")); + connect(save_as_act, &QAction::triggered, this, &MainWindow::showSaveAsDialog); settings_act = new QAction(tr("Settings..."), this); -#if defined(Q_OS_MAC) settings_act->setShortcut(QKeySequence::Preferences); settings_act->setMenuRole(QAction::PreferencesRole); -#endif - connect(settings_act, SIGNAL(triggered()), this, SLOT(showSettings())); + connect(settings_act, &QAction::triggered, this, &MainWindow::showSettings); - close_act = new QAction(QIcon(":/images/close.png"), tr("Close"), this); + close_act = new QAction(QIcon(QString::fromLatin1(":/images/close.png")), tr("Close"), this); close_act->setShortcut(QKeySequence::Close); close_act->setStatusTip(tr("Close this file")); - close_act->setWhatsThis("See more"); - connect(close_act, SIGNAL(triggered()), this, SLOT(closeFile())); + close_act->setWhatsThis(Util::makeWhatThis("file_menu.html")); + connect(close_act, &QAction::triggered, this, &MainWindow::closeFile); QAction* exit_act = new QAction(tr("E&xit"), this); exit_act->setShortcuts(QKeySequence::Quit); exit_act->setStatusTip(tr("Exit the application")); -#if defined(Q_OS_MAC) exit_act->setMenuRole(QAction::QuitRole); -#endif - exit_act->setWhatsThis("See more"); - connect(exit_act, SIGNAL(triggered()), qApp, SLOT(closeAllWindows())); + exit_act->setWhatsThis(Util::makeWhatThis("file_menu.html")); + connect(exit_act, &QAction::triggered, qApp, &QApplication::closeAllWindows); if (show_menu) + { file_menu = menuBar()->addMenu(tr("&File")); + } else { delete file_menu; file_menu = new QMenu(this); } - file_menu->setWhatsThis("See more"); + file_menu->setWhatsThis(Util::makeWhatThis("file_menu.html")); file_menu->addAction(new_act); file_menu->addAction(open_act); file_menu->addAction(save_act); @@ -300,38 +294,34 @@ void MainWindow::createFileMenu() file_menu->addAction(exit_act); general_toolbar = new QToolBar(tr("General")); - general_toolbar->setObjectName("General toolbar"); + general_toolbar->setObjectName(QString::fromLatin1("General toolbar")); general_toolbar->addAction(new_act); general_toolbar->addAction(open_act); general_toolbar->addAction(save_act); - save_act->setEnabled(false); - save_as_act->setEnabled(false); - close_act->setEnabled(false); + save_act->setEnabled(has_opened_file); + save_as_act->setEnabled(has_opened_file); + close_act->setEnabled(has_opened_file); updateRecentFileActions(); } void MainWindow::createHelpMenu() { // Help menu - QAction* manualAct = new QAction(QIcon(":/images/help.png"), tr("Open &Manual"), this); + QAction* manualAct = new QAction(QIcon(QString::fromLatin1(":/images/help.png")), tr("Open &Manual"), this); manualAct->setStatusTip(tr("Show the help file for this application")); manualAct->setShortcut(QKeySequence::HelpContents); - connect(manualAct, SIGNAL(triggered()), this, SLOT(showHelp())); + connect(manualAct, &QAction::triggered, this, &MainWindow::showHelp); - QAction* aboutAct = new QAction(tr("&About %1").arg(APP_NAME), this); + QAction* aboutAct = new QAction(tr("&About %1").arg(appName()), this); aboutAct->setStatusTip(tr("Show information about this application")); -#if defined(Q_OS_MAC) aboutAct->setMenuRole(QAction::AboutRole); -#endif - connect(aboutAct, SIGNAL(triggered()), this, SLOT(showAbout())); + connect(aboutAct, &QAction::triggered, this, &MainWindow::showAbout); QAction* aboutQtAct = new QAction(tr("About &Qt"), this); aboutQtAct->setStatusTip(tr("Show information about Qt")); -#if defined(Q_OS_MAC) aboutQtAct->setMenuRole(QAction::AboutQtRole); -#endif - connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt())); + connect(aboutQtAct, &QAction::triggered, qApp, QApplication::aboutQt); if (show_menu) { @@ -346,11 +336,19 @@ void MainWindow::createHelpMenu() void MainWindow::setCurrentPath(const QString& path) { - if (current_path != path) + Q_ASSERT(has_opened_file || path.isEmpty()); + + QString window_file_path; + current_path.clear(); + if (has_opened_file) { - current_path = QFileInfo(path).canonicalFilePath(); - updateWindowTitle(); + window_file_path = QFileInfo(path).canonicalFilePath(); + if (window_file_path.isEmpty()) + window_file_path = tr("Unsaved file"); + else + current_path = window_file_path; } + setWindowFilePath(window_file_path); } void MainWindow::setMostRecentlyUsedFile(const QString& path) @@ -361,7 +359,7 @@ void MainWindow::setMostRecentlyUsedFile(const QString& path) // Update least recently used directory const QString open_directory = QFileInfo(path).canonicalPath(); - QSettings().setValue("openFileDirectory", open_directory); + QSettings().setValue(QString::fromLatin1("openFileDirectory"), open_directory); // Update recent file lists QStringList files = settings.getSettingCached(Settings::General_RecentFilesList).toStringList(); @@ -373,32 +371,14 @@ void MainWindow::setMostRecentlyUsedFile(const QString& path) } } -void MainWindow::setHasOpenedFile(bool value) +void MainWindow::setHasUnsavedChanges(bool value) { - if (create_menu) + if (hasOpenedFile()) { - if (value && !has_opened_file) - { - save_act->setEnabled(true); - save_as_act->setEnabled(true); - close_act->setEnabled(true); - } - else if (!value && has_opened_file) - { - save_act->setEnabled(false); - save_as_act->setEnabled(false); - close_act->setEnabled(false); - } + has_unsaved_changes = value; + setAutosaveNeeded(has_unsaved_changes && !has_autosave_conflict); } - has_opened_file = value; - updateWindowTitle(); -} - -void MainWindow::setHasUnsavedChanges(bool value) -{ - has_unsaved_changes = value; - setAutosaveNeeded(has_unsaved_changes && !has_autosave_conflict); - updateWindowTitle(); + setWindowModified(has_unsaved_changes); } void MainWindow::setStatusBarText(const QString& text) @@ -429,6 +409,11 @@ void MainWindow::clearStatusBarMessage() #endif } +void MainWindow::setShortcutsBlocked(bool blocked) +{ + shortcuts_blocked = blocked; +} + bool MainWindow::closeFile() { bool closed = !has_opened_file || showSaveOnCloseDialog(); @@ -449,7 +434,7 @@ bool MainWindow::closeFile() bool MainWindow::event(QEvent* event) { - if (event->type() == QEvent::ShortcutOverride && disable_shortcuts) + if (event->type() == QEvent::ShortcutOverride && shortcutsBlocked()) event->accept(); return QMainWindow::event(event); @@ -512,13 +497,13 @@ bool MainWindow::showSaveOnCloseDialog() QMessageBox::StandardButton ret; if (!has_unsaved_changes && actual_path != autosavePath(currentPath())) { - ret = QMessageBox::warning(this, APP_NAME, + ret = QMessageBox::warning(this, appName(), tr("Do you want to remove the autosaved version?"), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); } else { - ret = QMessageBox::warning(this, APP_NAME, + ret = QMessageBox::warning(this, appName(), tr("The file has been modified.\n" "Do you want to save your changes?"), QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); @@ -539,9 +524,9 @@ bool MainWindow::showSaveOnCloseDialog() case QMessageBox::Save: if (!save()) return false; - // fall through + // fall through - case QMessageBox::Yes: + case QMessageBox::Yes: setHasAutosaveConflict(false); removeAutosaveFile(); break; @@ -565,10 +550,10 @@ void MainWindow::saveWindowSettings() #if !defined(Q_OS_ANDROID) QSettings settings; - settings.beginGroup("MainWindow"); - settings.setValue("pos", pos()); - settings.setValue("size", size()); - settings.setValue("maximized", isMaximized()); + settings.beginGroup(QString::fromLatin1("MainWindow")); + settings.setValue(QString::fromLatin1("pos"), pos()); + settings.setValue(QString::fromLatin1("size"), size()); + settings.setValue(QString::fromLatin1("maximized"), isMaximized()); settings.endGroup(); #endif } @@ -581,10 +566,10 @@ void MainWindow::loadWindowSettings() #else QSettings settings; - settings.beginGroup("MainWindow"); - QPoint pos = settings.value("pos", QPoint(100, 100)).toPoint(); - QSize size = settings.value("size", QSize(800, 600)).toSize(); - bool maximized = settings.value("maximized", false).toBool(); + settings.beginGroup(QString::fromLatin1("MainWindow")); + QPoint pos = settings.value(QString::fromLatin1("pos"), QPoint(100, 100)).toPoint(); + QSize size = settings.value(QString::fromLatin1("size"), QSize(800, 600)).toSize(); + bool maximized = settings.value(QString::fromLatin1("maximized"), false).toBool(); settings.endGroup(); move(pos); @@ -598,37 +583,17 @@ MainWindow* MainWindow::findMainWindow(const QString& file_name) { QString canonical_file_path = QFileInfo(file_name).canonicalFilePath(); if (canonical_file_path.isEmpty()) - return NULL; + return nullptr; - for (auto widget : qApp->topLevelWidgets()) + const auto top_level_widgets = qApp->topLevelWidgets(); + for (auto widget : top_level_widgets) { MainWindow* other = qobject_cast(widget); if (other && other->currentPath() == canonical_file_path) return other; } - return NULL; -} - -void MainWindow::updateWindowTitle() -{ - QString window_title = ""; - - if (has_unsaved_changes) - window_title += "(*)"; - - if (has_opened_file) - { - const QString current_file_path = currentPath(); - if (current_file_path.isEmpty()) - window_title += tr("Unsaved file") + " - "; - else - window_title += QFileInfo(current_file_path).fileName() + " - "; - } - - window_title += APP_NAME + " " + APP_VERSION; - - setWindowTitle(window_title); + return nullptr; } void MainWindow::showNewMapWizard() @@ -643,28 +608,39 @@ void MainWindow::showNewMapWizard() Map* new_map = new Map(); QString symbol_set_path = newMapDialog.getSelectedSymbolSetPath(); if (symbol_set_path.isEmpty()) + { new_map->setScaleDenominator(newMapDialog.getSelectedScale()); + } else { - new_map->loadFrom(symbol_set_path, this, NULL, true); + new_map->loadFrom(symbol_set_path, this, nullptr, true); if (new_map->getScaleDenominator() != newMapDialog.getSelectedScale()) { if (QMessageBox::question(this, tr("Warning"), tr("The selected map scale is 1:%1, but the chosen symbol set has a nominal scale of 1:%2.\n\nDo you want to scale the symbols to the selected scale?").arg(newMapDialog.getSelectedScale()).arg(new_map->getScaleDenominator()), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { - double factor = new_map->getScaleDenominator() / (double)newMapDialog.getSelectedScale(); + double factor = double(new_map->getScaleDenominator()) / newMapDialog.getSelectedScale(); new_map->scaleAllSymbols(factor); } new_map->setScaleDenominator(newMapDialog.getSelectedScale()); } + + for (int i = new_map->getNumSymbols(); i > 0; i = qMin(i, new_map->getNumSymbols())) + { + --i; + auto symbol = new_map->getSymbol(i); + if (symbol->isHidden() + && !new_map->existsObjectWithSymbol(symbol)) + { + new_map->deleteSymbol(i); + } + } } + new_map->setHasUnsavedChanges(false); + new_map->undoManager().clear(); - MainWindow* new_window; - if (has_opened_file) - new_window = new MainWindow(true); - else - new_window = this; - new_window->setController(new MapEditorController(MapEditorController::MapEditor, new_map)); + MainWindow* new_window = hasOpenedFile() ? new MainWindow() : this; + new_window->setController(new MapEditorController(MapEditorController::MapEditor, new_map), QString()); new_window->show(); new_window->raise(); @@ -675,11 +651,8 @@ void MainWindow::showNewMapWizard() void MainWindow::showOpenDialog() { QString path = getOpenFileName(this, tr("Open file"), FileFormat::AllFiles); - - if (path.isEmpty()) - return; - - openPath(path); + if (!path.isEmpty()) + openPath(path); } bool MainWindow::openPath(const QString &path) @@ -701,7 +674,7 @@ bool MainWindow::openPath(const QString &path) // Check a blocker that prevents immediate re-opening of crashing files. // Needed for stopping auto-loading a crashing file on startup. - static const QString reopen_blocker = "open_in_progress"; + static const QString reopen_blocker = QString::fromLatin1("open_in_progress"); QSettings settings; const QString open_in_progress(settings.value(reopen_blocker).toString()); if (open_in_progress == path) @@ -752,7 +725,7 @@ bool MainWindow::openPath(const QString &path) MainWindow* open_window = this; #if !defined(Q_OS_ANDROID) if (has_opened_file) - open_window = new MainWindow(true); + open_window = new MainWindow(); #endif open_window->setController(new_controller, path); @@ -770,14 +743,14 @@ bool MainWindow::openPath(const QString &path) // Assuming large screen. Android handled above. if (new_autosave_conflict) { - QDialog* autosave_dialog = new AutosaveDialog(path, autosave_path, new_actual_path, open_window, Qt::WindowTitleHint | Qt::CustomizeWindowHint); + auto autosave_dialog = new AutosaveDialog(path, autosave_path, new_actual_path, open_window, Qt::WindowTitleHint | Qt::CustomizeWindowHint); autosave_dialog->move(open_window->rect().right() - autosave_dialog->width(), open_window->rect().top()); autosave_dialog->show(); autosave_dialog->raise(); - connect(autosave_dialog, SIGNAL(pathSelected(QString)), open_window, SLOT(switchActualPath(QString))); - connect(open_window, SIGNAL(actualPathChanged(QString)), autosave_dialog, SLOT(setSelectedPath(QString))); - connect(open_window, SIGNAL(autosaveConflictResolved()), autosave_dialog, SLOT(autosaveConflictResolved())); + connect(autosave_dialog, &AutosaveDialog::pathSelected, open_window, &MainWindow::switchActualPath); + connect(open_window, &MainWindow::actualPathChanged, autosave_dialog, &AutosaveDialog::setSelectedPath); + connect(open_window, &MainWindow::autosaveConflictResolved, autosave_dialog, &AutosaveDialog::autosaveConflictResolved); } #endif @@ -796,7 +769,7 @@ void MainWindow::switchActualPath(const QString& path) int ret = QMessageBox::Ok; if (has_unsaved_changes) { - ret = QMessageBox::warning(this, APP_NAME, + ret = QMessageBox::warning(this, appName(), tr("The file has been modified.\n" "Do you want to discard your changes?"), QMessageBox::Discard | QMessageBox::Cancel); @@ -826,15 +799,14 @@ void MainWindow::openPathLater(const QString& path) void MainWindow::openPathBacklog() { - for (auto&& path : path_backlog) + for (const auto& path : qAsConst(path_backlog)) openPath(path); path_backlog.clear(); } void MainWindow::openRecentFile() { - QAction *action = qobject_cast(sender()); - if (action) + if (auto action = qobject_cast(sender())) openPath(action->data().toString()); } @@ -845,7 +817,7 @@ void MainWindow::updateRecentFileActions() QStringList files = Settings::getInstance().getSettingCached(Settings::General_RecentFilesList).toStringList(); - int num_recent_files = qMin(files.size(), (int)max_recent_files); + int num_recent_files = qMin(files.size(), max_recent_files); open_recent_menu->clear(); for (int i = 0; i < num_recent_files; ++i) { @@ -942,7 +914,7 @@ bool MainWindow::savePath(const QString &path) setHasAutosaveConflict(false); removeAutosaveFile(); - if (path != current_path) + if (path != currentPath()) { setCurrentPath(path); removeAutosaveFile(); @@ -957,7 +929,7 @@ QString MainWindow::getOpenFileName(QWidget* parent, const QString& title, FileF { // Get the saved directory to start in, defaulting to the user's home directory. QSettings settings; - QString open_directory = settings.value("openFileDirectory", QDir::homePath()).toString(); + QString open_directory = settings.value(QString::fromLatin1("openFileDirectory"), QDir::homePath()).toString(); // Build the list of supported file filters based on the file format registry QString filters, extensions; @@ -971,21 +943,21 @@ QString MainWindow::getOpenFileName(QWidget* parent, const QString& title, FileF if (filters.isEmpty()) { filters = format->filter(); - extensions = "*." % format->fileExtensions().join(" *."); + extensions = QLatin1String("*.") + format->fileExtensions().join(QString::fromLatin1(" *.")); } else { - filters = filters % ";;" % format->filter(); - extensions = extensions % " *." % format->fileExtensions().join(" *."); + filters = filters + QLatin1String(";;") + format->filter(); + extensions = extensions + QLatin1String(" *.") + format->fileExtensions().join(QString::fromLatin1(" *.")); } } } filters = - tr("All maps") % " (" % extensions % ");;" % - filters % ";;"; + tr("All maps") + QLatin1String(" (") + extensions + QLatin1String(");;") + + filters + QLatin1String(";;"); } - filters += tr("All files") % " (*.*)"; + filters += tr("All files") + QLatin1String(" (*.*)"); QString path = QFileDialog::getOpenFileName(parent, title, open_directory, filters); QFileInfo info(path); @@ -1004,7 +976,7 @@ bool MainWindow::showSaveAsDialog() { // revert to least recently used directory or home directory. QSettings settings; - save_directory = settings.value("openFileDirectory", QDir::homePath()).toString(); + save_directory = settings.value(QString::fromLatin1("openFileDirectory"), QDir::homePath()).toString(); } // Build the list of supported file filters based on the file format registry @@ -1016,11 +988,11 @@ bool MainWindow::showSaveAsDialog() if (filters.isEmpty()) filters = format->filter(); else - filters = filters % ";;" % format->filter(); + filters = filters + QLatin1String(";;") + format->filter(); } } - QString filter = NULL; // will be set to the selected filter by QFileDialog + QString filter; // will be set to the selected filter by QFileDialog QString path = QFileDialog::getSaveFileName(this, tr("Save file"), save_directory, filters, &filter); // On Windows, when the user enters "sample", we get "sample.omap *.xmap". @@ -1029,7 +1001,7 @@ bool MainWindow::showSaveAsDialog() // This results in an error later, because "*" is not a valid character. // But it is reasonable to apply the workaround to all platforms, // due to the special meaning of "*" in shell patterns. - const int extensions_quirk = path.indexOf(" *."); + const int extensions_quirk = path.indexOf(QLatin1String(" *.")); if (extensions_quirk >= 0) { path.truncate(extensions_quirk); @@ -1039,11 +1011,11 @@ bool MainWindow::showSaveAsDialog() return false; const FileFormat *format = FileFormats.findFormatByFilter(filter); - if (NULL == format) + if (!format) { QMessageBox::information(this, tr("Error"), - tr("File could not be saved:") % "\n" % - tr("There was a problem in determining the file format.") % "\n\n" % + tr("File could not be saved:") + QLatin1Char('\n') + + tr("There was a problem in determining the file format.") + QLatin1Char('\n') + QLatin1Char('\n') + tr("Please report this as a bug.") ); return false; } @@ -1051,11 +1023,11 @@ bool MainWindow::showSaveAsDialog() // Ensure that the provided filename has a correct file extension. // Among other things, this will ensure that FileFormats.formatForFilename() // returns the same thing the user selected in the dialog. -// QString selected_extension = "." % format->primaryExtension(); +// QString selected_extension = "." + format->primaryExtension(); QStringList selected_extensions(format->fileExtensions()); - selected_extensions.replaceInStrings(QRegExp("^"), "."); + selected_extensions.replaceInStrings(QRegExp(QString::fromLatin1("^")), QString::fromLatin1(".")); bool has_extension = false; - for (auto selected_extension : selected_extensions) + for (auto selected_extension : qAsConst(selected_extensions)) { if (path.endsWith(selected_extension, Qt::CaseInsensitive)) { @@ -1064,7 +1036,7 @@ bool MainWindow::showSaveAsDialog() } } if (!has_extension) - path.append(".").append(format->primaryExtension()); + path += QLatin1Char('.') + format->primaryExtension(); // Ensure that the file name matches the format. Q_ASSERT(format->fileExtensions().contains(QFileInfo(path).suffix())); // Fails when using different formats for import and export: @@ -1077,13 +1049,9 @@ void MainWindow::toggleFullscreenMode() { if (isFullScreen()) { + showNormal(); if (maximized_before_fullscreen) - { - showNormal(); showMaximized(); - } - else - showNormal(); } else { @@ -1107,7 +1075,7 @@ void MainWindow::showAbout() void MainWindow::showHelp() { #ifdef Q_OS_ANDROID - const QString manual_path = MapperResource::locate(MapperResource::MANUAL, "index.html"); + const QString manual_path = MapperResource::locate(MapperResource::MANUAL, QString::fromLatin1("index.html")); const QUrl help_url = QUrl::fromLocalFile(manual_path); TextBrowserDialog help_dialog(help_url, this); help_dialog.exec(); @@ -1118,16 +1086,16 @@ void MainWindow::showHelp() void MainWindow::linkClicked(const QString &link) { - if (link.compare("settings:", Qt::CaseInsensitive) == 0) + if (link.compare(QLatin1String("settings:"), Qt::CaseInsensitive) == 0) showSettings(); - else if (link.compare("help:", Qt::CaseInsensitive) == 0) + else if (link.compare(QLatin1String("help:"), Qt::CaseInsensitive) == 0) showHelp(); - else if (link.compare("about:", Qt::CaseInsensitive) == 0) + else if (link.compare(QLatin1String("about:"), Qt::CaseInsensitive) == 0) showAbout(); - else if (link.startsWith("examples:", Qt::CaseInsensitive)) + else if (link.startsWith(QLatin1String("examples:"), Qt::CaseInsensitive)) { auto example = link.midRef(9); - openPathLater(MapperResource::locate(MapperResource::EXAMPLE) % '/' % example); + openPathLater(MapperResource::locate(MapperResource::EXAMPLE) + QLatin1Char('/') + example); } else QDesktopServices::openUrl(link); @@ -1142,13 +1110,7 @@ bool MainWindow::eventFilter(QObject *object, QEvent *event) case QEvent::WhatsThisClicked: { QWhatsThisClickedEvent* e = static_cast(event); - QStringList parts = e->href().split("#"); - if(parts.size() == 0) - Util::showHelp(this); - else if(parts.size() == 1) - Util::showHelp(this, parts.at(0)); - else if(parts.size() == 2) - Util::showHelp(this, parts.at(0), parts.at(1)); + Util::showHelp(this, e->href()); }; break; #if defined(Q_OS_ANDROID) diff --git a/src/gui/main_window.h b/src/gui/main_window.h index 6e462781a..38fba7f8e 100644 --- a/src/gui/main_window.h +++ b/src/gui/main_window.h @@ -1,6 +1,6 @@ /* * Copyright 2012, 2013 Thomas Schöps - * Copyright 2014 Thomas Schöps, Kai Pastor + * Copyright 2013-2016 Kai Pastor * * This file is part of OpenOrienteering. * @@ -19,8 +19,8 @@ */ -#ifndef _OPENORIENTEERING_MAIN_WINDOW_H_ -#define _OPENORIENTEERING_MAIN_WINDOW_H_ +#ifndef OPENORIENTEERING_MAIN_WINDOW_H +#define OPENORIENTEERING_MAIN_WINDOW_H #include @@ -35,96 +35,137 @@ QT_END_NAMESPACE class MainWindowController; -/** The MainWindow class provides the generic application window. - * It always has an active controller (class MainWindowController) - * which provides the specific window content and behaviours. - * The controller can be exchanged while the window is visible. +/** + * The MainWindow class provides the generic application window. + * + * It always has an active controller (class MainWindowController) + * which provides the specific window content and behaviours. + * The controller can be exchanged while the window is visible. */ class MainWindow : public QMainWindow, private Autosave { Q_OBJECT public: - /** Creates a new main window. - * FIXME: as_main_window seems to be contradictory and is used only - * with value false (in SymbolSettingDialog). - * @param as_main_window if false, disables the loading of save windows geometry and hides the bottom-right handle for resizing. + /** + * Creates a new main window. + */ + explicit MainWindow(QWidget* parent = nullptr, Qt::WindowFlags flags = Qt::WindowFlags()); + +private: + /** + * Creates a new main window. + * + * The flag as_main_window is a contradiction to the general intent of this + * class. The value fals is used only once, in SymbolSettingDialog. For this + * case, it disables some features such as the main menu. + * + * \todo Refactor to remove the flag as_main_window. */ - explicit MainWindow(bool as_main_window = true); + explicit MainWindow(bool as_main_window, QWidget* parent = nullptr, Qt::WindowFlags flags = Qt::WindowFlags()); + + friend class SymbolSettingDialog; +public: /** Destroys a main window. */ - virtual ~MainWindow(); + ~MainWindow() override; - /** Returns the application's name. */ - const QString& appName() const; + /** Returns the application's localized name. */ + QString appName() const; /** * Returns whether the window is operating in mobile mode. * - * Mobile mode is the default on Android. The default may be overwritten by + * On the desktop, the default (desktop) mode may be overwritten by * setting the environment variable MAPPER_MOBILE_GUI to 0 or 1. + * + * For Android, this evaluates to constexpr true so that the compiler + * may optimize away desktop code in conditional blocks. */ - bool mobileMode() const; +#ifndef Q_OS_ANDROID + static bool mobileMode(); +#else + static constexpr bool mobileMode() { return true; } +#endif + + /** + * Changes the controller. + * + * The new controller does not edit a file. + */ + void setController(MainWindowController* new_controller); - /** Change the controller to new_controller. */ - void setController(MainWindowController* new_controller, const QString& path = QString()); + /** + * Changes the controller. + * + * The new controller edits the file with the given path. + * The path may be empty for a new (unnamed) file. + */ + void setController(MainWindowController* new_controller, const QString& path); +private: + void setController(MainWindowController* new_controller, bool has_file); + +public: /** Returns the current controller. */ - inline MainWindowController* getController() const {return controller;} + MainWindowController* getController() const; /** Returns the canonical path of the currently open file or * an empty string if no file is open. */ - inline const QString& currentPath() const {return current_path;} + const QString& currentPath() const; - /** @brief Registers the given path as most recently used file. + /** Registers the given path as most recently used file. + * * The path is added at (or moved to) the top of the list of most recently * used files, and the directory is saved as most recently used directory. */ static void setMostRecentlyUsedFile(const QString& path); - /** Sets the opened-file state to value. */ - void setHasOpenedFile(bool value); - /** Returns true if a file is opened in this main window. */ - inline bool hasOpenedFile() const {return has_opened_file;} + bool hasOpenedFile() const; /** Returns true if the opened file is marked as having unsaved changes. */ - inline bool hasUnsavedChanges() const {return has_unsaved_changes;} + bool hasUnsavedChanges() const; /** Sets the text in the status bar. */ void setStatusBarText(const QString& text); + /** Shows a temporary message in the status bar. */ void showStatusBarMessage(const QString& text, int timeout = 0); + /** Clears temporary messages set in the status bar with showStatusBarMessage(). */ void clearStatusBarMessage(); - /** Enable or disable shortcuts. - * During text input, it may be neccessary to disable shortcuts. - * @param enable true for enabling shortcuts, false for disabling. + /** + * Blocks shortcuts. + * + * During text input, it may be neccessary to disable shortcuts. + * + * @param blocked true for blocking shortcuts, false for normal behaviour. */ - inline void setShortcutsEnabled(bool enable) {disable_shortcuts = !enable;} + void setShortcutsBlocked(bool blocked); /** Returns true if shortcuts are currently disabled. */ - inline bool areShortcutsDisabled() const {return disable_shortcuts;} + bool shortcutsBlocked() const; /** Returns the main window's file menu so that it can be extended. */ - inline QMenu* getFileMenu() const {return file_menu;} + QMenu* getFileMenu() const; /** Returns an QAction which serves as extension point in the file menu. */ - inline QAction* getFileMenuExtensionAct() const {return settings_act;} + QAction* getFileMenuExtensionAct() const; /** Returns the save action. */ - inline QAction* getSaveAct() const {return save_act;} + QAction* getSaveAct() const; /** Returns the close action. */ - inline QAction* getCloseAct() const {return close_act;} + QAction* getCloseAct() const; /** @@ -133,7 +174,7 @@ Q_OBJECT * The MainWindowController is responsible to add it to the main window. * It will be destroyed (and recreated) when the controller changes. */ - inline QToolBar* getGeneralToolBar() const { return general_toolbar; } + QToolBar* getGeneralToolBar() const; /** Open the file with the given path after all events have been processed. @@ -155,6 +196,7 @@ Q_OBJECT /** * Sets the MainWindow's effective central widget. + * * Any previously set widget will be hidden and scheduled for deletion. * * Hides an implementation in QMainWindow which causes problems with @@ -181,50 +223,65 @@ Q_OBJECT void setHomeScreenDisabled(bool disabled); public slots: - /** Show a wizard for creating new maps. - * May open a new main window. + /** + * Show a wizard for creating new maps. + * + * May open a new main window. */ void showNewMapWizard(); - /** Show a file-open dialog and load the select file. - * May open a new main window. - * If loading is successful, the selected path will become - * the [new] window's current path. + /** + * Show a file-open dialog and load the select file. + * + * May open a new main window. + * If loading is successful, the selected path will become + * the [new] window's current path. */ void showOpenDialog(); - /** Show a file-save dialog. - * If saving is successful, the selected path will become - * this window's current path. - * @return true if saving was succesful, false otherwise + /** + * Show a file-save dialog. + * + * If saving is successful, the selected path will become + * this window's current path. + * + * @return true if saving was succesful, false otherwise */ bool showSaveAsDialog(); - /** Open the file with the given path. - * May open a new main window. - * If loading is successful, the selected path will become - * the [new] window's current path. - * @return true if loading was succesful, false otherwise + /** + * Open the file with the given path. + * + * May open a new main window. + * If loading is successful, the selected path will become + * the [new] window's current path. + * + * @return true if loading was succesful, false otherwise */ bool openPath(const QString &path); - /** Open the file specified in the sending action's data. - * This is intended for opening recent files. + /** + * Open the file specified in the sending action's data. + * + * This is intended for opening recent files. */ void openRecentFile(); - /** Notify the main window of a change to the list of recent files. + /** + * Notify the main window of a change to the list of recent files. */ void updateRecentFileActions(); - /** Save the current content to the current path. - * This will trigger a file-save dialog if the current path is not set (i.e. empty). + /** + * Save the current content to the current path. + * + * This will trigger a file-save dialog if the current path is not set (i.e. empty). */ bool save(); /** Save the current content to the current path. */ - virtual Autosave::AutosaveResult autosave(); + Autosave::AutosaveResult autosave() override; /** * Close the file currently opened. @@ -264,6 +321,11 @@ public slots: /** * Notifies this window of unsaved changes. + * + * If the controller was set as having an opened file, setting this value to + * true will start the autosave countdown if the previous value was false. + * + * This will update the window title via QWidget::setWindowModified(). */ void setHasUnsavedChanges(bool value); @@ -310,16 +372,17 @@ protected slots: protected: /** - * @brief Sets the path of the file edited by this windows' controller. + * Sets the path of the file edited by this windows' controller. * - * This will trigger updates to the window title, - * to the list of recently used files, and - * to the least recently used directory. + * This will update the window title via QWidget::setWindowFilePath(). + * + * If the controller was not set as having an opened file, + * the path must be empty. */ void setCurrentPath(const QString& path); /** - * @brief Notifies the windows of autosave conflicts. + * Notifies the windows of autosave conflicts. * * An autosave conflict is the situation where a autosaved file exists * when the original file is opened. This autosaved file indicates that @@ -329,28 +392,30 @@ protected slots: void setHasAutosaveConflict(bool value); /** - * @brief Removes the autosave file if it exists. + * Removes the autosave file if it exists. * * Returns true if the file was removed or didn't exist, false otherwise. */ bool removeAutosaveFile() const; - virtual bool event(QEvent* event); - virtual void closeEvent(QCloseEvent *event); - virtual void keyPressEvent(QKeyEvent* event); - virtual void keyReleaseEvent(QKeyEvent* event); + bool event(QEvent* event) override; + void closeEvent(QCloseEvent *event) override; + void keyPressEvent(QKeyEvent* event) override; + void keyReleaseEvent(QKeyEvent* event) override; - virtual bool eventFilter(QObject* object, QEvent* event); + bool eventFilter(QObject* object, QEvent* event) override; private: - enum { - max_recent_files = 10 - }; + static constexpr int max_recent_files = 10; - /** If this main window has an opened file with unsaved changes, shows - * a dialog which lets the user save the file, discard the changes or - * cancel. - * Returns true if the window can be closed, false otherwise. + /** + * Conditionally shows a dialog for saving pending changes. + * + * If this main window has an opened file with unsaved changes, shows + * a dialog which lets the user save the file, discard the changes or + * cancel. + * + * Returns true if the window can be closed, false otherwise. */ bool showSaveOnCloseDialog(); @@ -362,8 +427,6 @@ protected slots: void loadWindowSettings(); - void updateWindowTitle(); - void createFileMenu(); void createHelpMenu(); @@ -372,14 +435,13 @@ protected slots: /// The active controller MainWindowController* controller; - bool create_menu; + const bool create_menu; bool show_menu; - bool disable_shortcuts; + bool shortcuts_blocked; QToolBar* general_toolbar; QMenu* file_menu; QAction* save_act; - QAction* save_as_act; QMenu* open_recent_menu; bool open_recent_menu_inserted; QAction* recent_file_act[max_recent_files]; @@ -416,6 +478,66 @@ protected slots: // ### MainWindow inline code ### +inline +MainWindowController* MainWindow::getController() const +{ + return controller; +} + +inline +const QString& MainWindow::currentPath() const +{ + return current_path; +} + +inline +bool MainWindow::hasOpenedFile() const +{ + return has_opened_file; +} + +inline +bool MainWindow::hasUnsavedChanges() const +{ + return has_unsaved_changes; +} + +inline +bool MainWindow::shortcutsBlocked() const +{ + return shortcuts_blocked; +} + +inline +QMenu* MainWindow::getFileMenu() const +{ + return file_menu; +} + +inline +QAction* MainWindow::getFileMenuExtensionAct() const +{ + return settings_act; +} + +inline +QAction* MainWindow::getSaveAct() const +{ + return save_act; +} + +inline +QAction* MainWindow::getCloseAct() const +{ + return close_act; +} + +inline +QToolBar* MainWindow::getGeneralToolBar() const +{ + return general_toolbar; +} + inline bool MainWindow::homeScreenDisabled() const { diff --git a/src/gui/print_widget.cpp b/src/gui/print_widget.cpp index 5e3186eb4..fe6b92faa 100644 --- a/src/gui/print_widget.cpp +++ b/src/gui/print_widget.cpp @@ -1,6 +1,6 @@ /* * Copyright 2012, 2013 Thomas Schöps - * Copyright 2012-2015 Kai Pastor + * Copyright 2012-2016 Kai Pastor * * This file is part of OpenOrienteering. * @@ -45,8 +45,11 @@ #include #include +#include + #include "main_window.h" #include "print_progress_dialog.h" +#include "print_tool.h" #include "../core/map_printer.h" #include "../map.h" #include "../map_editor.h" @@ -54,13 +57,13 @@ #include "../settings.h" #include "../util.h" #include "../util_gui.h" +#include "../util/backports.h" #include "../util/scoped_signals_blocker.h" -#include "print_tool.h" namespace { - QToolButton* createPrintModeButton(const QIcon& icon, const QString& label, QWidget* parent = NULL) + QToolButton* createPrintModeButton(const QIcon& icon, const QString& label, QWidget* parent = nullptr) { static const QSize icon_size(48,48); QToolButton* button = new QToolButton(parent); @@ -77,17 +80,17 @@ namespace //### PrintWidget ### PrintWidget::PrintWidget(Map* map, MainWindow* main_window, MapView* main_view, MapEditorController* editor, QWidget* parent) -: QWidget(parent), - task(UNDEFINED_TASK), - map(map), - map_printer(new MapPrinter(*map, main_view)), - main_window(main_window), - main_view(main_view), - editor(editor), - print_tool(NULL), - active(false) +: QWidget { parent } +, task { UNDEFINED_TASK } +, map { map } +, map_printer { new MapPrinter(*map, main_view) } +, main_window { main_window } +, main_view { main_view } +, editor { editor } +, print_tool { nullptr } +, active { false } { - Q_ASSERT(main_window != NULL); + Q_ASSERT(main_window); layout = new QFormLayout(); @@ -95,6 +98,17 @@ PrintWidget::PrintWidget(Map* map, MainWindow* main_window, MapView* main_view, target_combo->setMinimumWidth(1); // Not zero, but not as long as the items layout->addRow(Util::Headline::create(tr("Printer:")), target_combo); + if (PlatformPrinterProperties::dialogSupported()) + { + printer_properties_button = new QToolButton(); + printer_properties_button->setText(tr("Properties")); + layout->addRow(nullptr, printer_properties_button); + } + else + { + printer_properties_button = nullptr; + } + paper_size_combo = new QComboBox(); layout->addRow(tr("Page format:"), paper_size_combo); @@ -105,11 +119,11 @@ PrintWidget::PrintWidget(Map* map, MainWindow* main_window, MapView* main_view, page_width_edit = Util::SpinBox::create(1, 0.1, 1000.0, tr("mm"), 1.0); page_width_edit->setEnabled(false); page_size_layout->addWidget(page_width_edit, 1); - page_size_layout->addWidget(new QLabel("x"), 0); + page_size_layout->addWidget(new QLabel(QString::fromLatin1("x")), 0); page_height_edit = Util::SpinBox::create(1, 0.1, 1000.0, tr("mm"), 1.0); page_height_edit->setEnabled(false); page_size_layout->addWidget(page_height_edit, 1); - layout->addRow("", page_size_widget); + layout->addRow({}, page_size_widget); page_orientation_widget = new QWidget(); QBoxLayout* page_orientation_layout = new QHBoxLayout(); @@ -161,9 +175,9 @@ PrintWidget::PrintWidget(Map* map, MainWindow* main_window, MapView* main_view, mode_widget->setLayout(mode_layout); mode_layout->setMargin(0); - vector_mode_button = createPrintModeButton(QIcon(":/images/print-mode-vector.png"), tr("Vector\ngraphics")); - raster_mode_button = createPrintModeButton(QIcon(":/images/print-mode-raster.png"), tr("Raster\ngraphics")); - separations_mode_button = createPrintModeButton(QIcon(":/images/print-mode-separations.png"), tr("Color\nseparations")); + vector_mode_button = createPrintModeButton(QIcon(QString::fromLatin1(":/images/print-mode-vector.png")), tr("Vector\ngraphics")); + raster_mode_button = createPrintModeButton(QIcon(QString::fromLatin1(":/images/print-mode-raster.png")), tr("Raster\ngraphics")); + separations_mode_button = createPrintModeButton(QIcon(QString::fromLatin1(":/images/print-mode-separations.png")), tr("Color\nseparations")); vector_mode_button->setChecked(true); QButtonGroup* mode_button_group = new QButtonGroup(this); @@ -180,15 +194,15 @@ PrintWidget::PrintWidget(Map* map, MainWindow* main_window, MapView* main_view, dpi_combo = new QComboBox(); dpi_combo->setEditable(true); - dpi_combo->setValidator(new QRegExpValidator(QRegExp("^[1-9]\\d{1,4} dpi$|^[1-9]\\d{1,4}$"), dpi_combo)); + dpi_combo->setValidator(new QRegExpValidator(QRegExp(QString::fromLatin1("^[1-9]\\d{1,4} dpi$|^[1-9]\\d{1,4}$")), dpi_combo)); // TODO: Implement spinbox-style " dpi" suffix layout->addRow(tr("Resolution:"), dpi_combo); different_scale_check = new QCheckBox(tr("Print in different scale:")); // Limit the difference between nominal and printing scale in order to limit the number of page breaks. - int min_scale = qMax((unsigned int)1, map->getScaleDenominator() / 10000 * 100); - different_scale_edit = Util::SpinBox::create(min_scale, std::numeric_limits::max(), "", 500); - different_scale_edit->setPrefix("1 : "); + int min_scale = qMax(1, int(map->getScaleDenominator() / 10000) * 100); + different_scale_edit = Util::SpinBox::create(min_scale, std::numeric_limits::max(), {}, 500); + different_scale_edit->setPrefix(QString::fromLatin1("1 : ")); different_scale_edit->setEnabled(false); int different_scale_height = qMax( different_scale_edit->minimumSizeHint().height(), @@ -255,53 +269,54 @@ PrintWidget::PrintWidget(Map* map, MainWindow* main_window, MapView* main_view, setLayout(outer_layout); - connect(target_combo, SIGNAL(currentIndexChanged(int)), this, SLOT(targetChanged(int))); - connect(paper_size_combo, SIGNAL(currentIndexChanged(int)), this, SLOT(paperSizeChanged(int))); - connect(page_width_edit, SIGNAL(valueChanged(double)), this, SLOT(paperDimensionsChanged())); - connect(page_orientation_group, SIGNAL(buttonClicked(int)), this, SLOT(pageOrientationChanged(int))); - connect(page_height_edit, SIGNAL(valueChanged(double)), this, SLOT(paperDimensionsChanged())); - - connect(top_edit, SIGNAL(valueChanged(double)), this, SLOT(printAreaMoved())); - connect(left_edit, SIGNAL(valueChanged(double)), this, SLOT(printAreaMoved())); - connect(width_edit, SIGNAL(valueChanged(double)), this, SLOT(printAreaResized())); - connect(height_edit, SIGNAL(valueChanged(double)), this, SLOT(printAreaResized())); - connect(overlap_edit, SIGNAL(valueChanged(double)), this, SLOT(overlapEdited(double))); - - connect(mode_button_group, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(printModeChanged(QAbstractButton*))); - connect(dpi_combo->lineEdit(), SIGNAL(editingFinished()), this, SLOT(resolutionEdited())); - connect(different_scale_check, SIGNAL(clicked(bool)), this, SLOT(differentScaleClicked(bool))); - connect(different_scale_edit, SIGNAL(valueChanged(int)), this, SLOT(differentScaleEdited(int))); - connect(show_templates_check, SIGNAL(clicked(bool)), this, SLOT(showTemplatesClicked(bool))); - connect(show_grid_check, SIGNAL(clicked(bool)), this, SLOT(showGridClicked(bool))); - connect(overprinting_check, SIGNAL(clicked(bool)), this, SLOT(overprintingClicked(bool))); + connect(target_combo, QOverload::of(&QComboBox::currentIndexChanged), this, &PrintWidget::targetChanged); + if (printer_properties_button) + connect(printer_properties_button, &QAbstractButton::clicked, this, &PrintWidget::propertiesClicked, Qt::QueuedConnection); + connect(paper_size_combo, QOverload::of(&QComboBox::currentIndexChanged), this, &PrintWidget::paperSizeChanged); + connect(page_width_edit, QOverload::of(&QDoubleSpinBox::valueChanged), this, &PrintWidget::paperDimensionsChanged); + connect(page_orientation_group, QOverload::of(&QButtonGroup::buttonClicked), this, &PrintWidget::pageOrientationChanged); + connect(page_height_edit, QOverload::of(&QDoubleSpinBox::valueChanged), this, &PrintWidget::paperDimensionsChanged); + + connect(top_edit, QOverload::of(&QDoubleSpinBox::valueChanged), this, &PrintWidget::printAreaMoved); + connect(left_edit, QOverload::of(&QDoubleSpinBox::valueChanged), this, &PrintWidget::printAreaMoved); + connect(width_edit, QOverload::of(&QDoubleSpinBox::valueChanged), this, &PrintWidget::printAreaResized); + connect(height_edit, QOverload::of(&QDoubleSpinBox::valueChanged), this, &PrintWidget::printAreaResized); + connect(overlap_edit, QOverload::of(&QDoubleSpinBox::valueChanged), this, &PrintWidget::overlapEdited); + + connect(mode_button_group, QOverload::of(&QButtonGroup::buttonClicked), this, &PrintWidget::printModeChanged); + connect(dpi_combo->lineEdit(), &QLineEdit::editingFinished, this, &PrintWidget::resolutionEdited); + connect(different_scale_check, &QAbstractButton::clicked, this, &PrintWidget::differentScaleClicked); + connect(different_scale_edit, QOverload::of(&QSpinBox::valueChanged), this, &PrintWidget::differentScaleEdited); + connect(show_templates_check, &QAbstractButton::clicked, this, &PrintWidget::showTemplatesClicked); + connect(show_grid_check, &QAbstractButton::clicked, this, &PrintWidget::showGridClicked); + connect(overprinting_check, &QAbstractButton::clicked, this, &PrintWidget::overprintingClicked); connect(color_mode_combo, &QComboBox::currentTextChanged, this, &PrintWidget::colorModeChanged); - connect(preview_button, SIGNAL(clicked(bool)), this, SLOT(previewClicked())); - connect(print_button, SIGNAL(clicked(bool)), this, SLOT(printClicked())); - connect(export_button, SIGNAL(clicked(bool)), this, SLOT(printClicked())); - connect(close_button, SIGNAL(clicked(bool)), this, SIGNAL(closeClicked())); + connect(preview_button, &QAbstractButton::clicked, this, &PrintWidget::previewClicked); + connect(print_button, &QAbstractButton::clicked, this, &PrintWidget::printClicked); + connect(export_button, &QAbstractButton::clicked, this, &PrintWidget::printClicked); + connect(close_button, &QAbstractButton::clicked, this, &PrintWidget::closeClicked); policy = map_printer->config().single_page_print_area ? SinglePage : CustomArea; policy_combo->setCurrentIndex(policy_combo->findData(policy)); - connect(policy_combo, SIGNAL(currentIndexChanged(int)), this, SLOT(printAreaPolicyChanged(int))); + connect(policy_combo, QOverload::of(&QComboBox::currentIndexChanged), this, &PrintWidget::printAreaPolicyChanged); center_check->setChecked(map_printer->config().center_print_area); - connect(center_check, SIGNAL(clicked(bool)), this, SLOT(applyCenterPolicy())); + connect(center_check, &QAbstractButton::clicked, this, &PrintWidget::applyCenterPolicy); setPageFormat(map_printer->getPageFormat()); - connect(map_printer, SIGNAL(pageFormatChanged(const MapPrinterPageFormat&)), - this, SLOT(setPageFormat(const MapPrinterPageFormat&))); + connect(map_printer, &MapPrinter::pageFormatChanged, this, &PrintWidget::setPageFormat); - connect(map_printer, SIGNAL(optionsChanged(const MapPrinterOptions&)), this, SLOT(setOptions(const MapPrinterOptions&))); + connect(map_printer, &MapPrinter::optionsChanged, this, &PrintWidget::setOptions); spotColorPresenceChanged(map->hasSpotColors()); - connect(map, SIGNAL(spotColorPresenceChanged(bool)), this, SLOT(spotColorPresenceChanged(bool))); + connect(map, &Map::spotColorPresenceChanged, this, &PrintWidget::spotColorPresenceChanged); setPrintArea(map_printer->getPrintArea()); - connect(map_printer, SIGNAL(printAreaChanged(QRectF)), this, SLOT(setPrintArea(QRectF))); + connect(map_printer, &MapPrinter::printAreaChanged, this, &PrintWidget::setPrintArea); - connect(map_printer, SIGNAL(targetChanged(const QPrinterInfo*)), this, SLOT(setTarget(const QPrinterInfo*))); + connect(map_printer, &MapPrinter::targetChanged, this, &PrintWidget::setTarget); - connect(this, SIGNAL(finished(int)), this, SLOT(savePrinterConfig())); + connect(this, &PrintWidget::finished, this, &PrintWidget::savePrinterConfig); } PrintWidget::~PrintWidget() @@ -367,7 +382,7 @@ void PrintWidget::setTask(PrintWidget::TaskFlags type) break; default: - emit taskChanged(QString::null); + emit taskChanged(QString{}); } } } @@ -401,7 +416,7 @@ void PrintWidget::setActive(bool active) // Save the current state of the map view. saved_view_state.clear(); QXmlStreamWriter writer(&saved_view_state); - main_view->save(writer, QLatin1String("saved_view"), true); + main_view->save(writer, QLatin1String("saved_view")); editor->setViewOptionsEnabled(false); @@ -432,11 +447,13 @@ void PrintWidget::setActive(bool active) print_tool = new PrintTool(editor, map_printer); } editor->setOverrideTool(print_tool); + editor->setEditingInProgress(true); } else { - editor->setOverrideTool(NULL); - print_tool = NULL; + editor->setEditingInProgress(false); + editor->setOverrideTool(nullptr); + print_tool = nullptr; // Restore view QXmlStreamReader reader(saved_view_state); @@ -454,7 +471,7 @@ void PrintWidget::updateTargets() { QVariant current_target = target_combo->itemData(target_combo->currentIndex()); const QPrinterInfo* saved_printer = map_printer->getTarget(); - const QString saved_printer_name = (saved_printer == NULL) ? "" : saved_printer->printerName(); + const QString saved_printer_name = saved_printer ? saved_printer->printerName() : QString{}; int saved_target_index = -1; int default_printer_index = -1; { @@ -464,7 +481,7 @@ void PrintWidget::updateTargets() if (task == PRINT_TASK) { // Exporters - target_combo->addItem(tr("Save to PDF"), QVariant((int)PdfExporter)); + target_combo->addItem(tr("Save to PDF"), QVariant(int(PdfExporter))); target_combo->insertSeparator(target_combo->count()); target_combo->setCurrentIndex(0); @@ -515,9 +532,9 @@ void PrintWidget::setTarget(const QPrinterInfo* target) { for (; target_index >= 0; target_index--) { - if (target != NULL && printers[target_index].printerName() == target->printerName()) + if (target && printers[target_index].printerName() == target->printerName()) break; - else if (target == NULL) + else if (!target) break; } } @@ -527,7 +544,7 @@ void PrintWidget::setTarget(const QPrinterInfo* target) updateResolutions(target); bool supports_pages = (target != MapPrinter::imageTarget()); - bool supports_copies = (supports_pages && target != NULL && QPrinter(*target).supportsMultipleCopies()); + bool supports_copies = (supports_pages && target && QPrinter(*target).supportsMultipleCopies()); copies_edit->setEnabled(supports_copies); layout->labelForField(copies_edit)->setEnabled(supports_copies); @@ -536,6 +553,8 @@ void PrintWidget::setTarget(const QPrinterInfo* target) print_button->setDefault(is_printer); export_button->setVisible(!is_printer); export_button->setDefault(!is_printer); + if (printer_properties_button) + printer_properties_button->setEnabled(is_printer); bool is_image_target = target == MapPrinter::imageTarget(); vector_mode_button->setEnabled(!is_image_target); @@ -557,9 +576,9 @@ void PrintWidget::targetChanged(int index) const int target_index = target_combo->itemData(index).toInt(); Q_ASSERT(target_index >= -2); - Q_ASSERT(target_index < (int)printers.size()); + Q_ASSERT(target_index < printers.size()); - const QPrinterInfo* target = NULL; + const QPrinterInfo* target = nullptr; if (target_index == PdfExporter) target = MapPrinter::pdfTarget(); else if (target_index == ImageExporter) @@ -570,7 +589,17 @@ void PrintWidget::targetChanged(int index) const map_printer->setTarget(target); } - +// slot +void PrintWidget::propertiesClicked() +{ + if (map_printer && map_printer->isPrinter()) + { + auto printer = map_printer->makePrinter(); + Q_ASSERT(printer->outputFormat() == QPrinter::NativeFormat); + if (PlatformPrinterProperties::execDialog(printer.get(), this) == QDialog::Accepted) + map_printer->takePrinterSettings(printer.get()); + } +} void PrintWidget::updatePaperSizes(const QPrinterInfo* target) const { @@ -582,12 +611,12 @@ void PrintWidget::updatePaperSizes(const QPrinterInfo* target) const paper_size_combo->clear(); QList size_list; - if (target != NULL) + if (target) size_list = target->supportedPaperSizes(); if (size_list.isEmpty()) size_list = defaultPaperSizes(); - for (auto size : size_list) + for (auto size : qAsConst(size_list)) { if (size == QPrinter::Custom) have_custom_size = true; // add it once after all other entires @@ -598,7 +627,7 @@ void PrintWidget::updatePaperSizes(const QPrinterInfo* target) const if (have_custom_size) paper_size_combo->addItem(toString(QPrinter::Custom), QPrinter::Custom); - int paper_size_index = paper_size_combo->findData((int)map_printer->getPageFormat().paper_size); + int paper_size_index = paper_size_combo->findData(map_printer->getPageFormat().paper_size); if (!prev_paper_size_name.isEmpty()) { paper_size_index = paper_size_combo->findText(prev_paper_size_name); @@ -633,7 +662,7 @@ void PrintWidget::paperSizeChanged(int index) const { if (index >= 0) { - QPrinter::PaperSize paper_size = (QPrinter::PaperSize)paper_size_combo->itemData(index).toInt(); + QPrinter::PaperSize paper_size = QPrinter::PaperSize(paper_size_combo->itemData(index).toInt()); map_printer->setPaperSize(paper_size); } } @@ -658,7 +687,7 @@ void PrintWidget::pageOrientationChanged(int id) const // slot void PrintWidget::printAreaPolicyChanged(int index) { - policy = (PrintAreaPolicy)policy_combo->itemData(index).toInt(); + policy = PrintAreaPolicy(policy_combo->itemData(index).toInt()); applyPrintAreaPolicy(); } @@ -853,33 +882,29 @@ void PrintWidget::setOptions(const MapPrinterOptions& options) checkTemplateConfiguration(); updateColorMode(); - static QString dpi_template("%1 " + tr("dpi")); + static QString dpi_template(QLatin1String("%1 ") + tr("dpi")); dpi_combo->setEditText(dpi_template.arg(options.resolution)); - if (different_scale_edit->value() != (int)options.scale) - { - different_scale_edit->setValue(options.scale); - if (options.scale != map->getScaleDenominator()) - { - different_scale_check->setChecked(true); - different_scale_edit->setEnabled(true); - } - applyPrintAreaPolicy(); - } - else + if (options.scale != map->getScaleDenominator()) { - applyCenterPolicy(); + different_scale_check->setChecked(true); + different_scale_edit->setEnabled(true); } + + auto scale = int(options.scale); + different_scale_edit->setValue(scale); + differentScaleEdited(scale); + main_view->updateAllMapWidgets(); } void PrintWidget::updateResolutions(const QPrinterInfo* target) const { - static QList default_resolutions(QList() << 150 << 300 << 600 << 1200); + static const QList default_resolutions(QList() << 150 << 300 << 600 << 1200); // Numeric resolution list QList supported_resolutions; - if (target != NULL) + if (target) { QPrinter pr(*target, QPrinter::HighResolution); supported_resolutions = pr.supportedResolutions(); @@ -893,9 +918,9 @@ void PrintWidget::updateResolutions(const QPrinterInfo* target) const supported_resolutions = default_resolutions; // Resolution list item with unit "dpi" - static QString dpi_template("%1 " + tr("dpi")); + static QString dpi_template(QLatin1String("%1 ") + tr("dpi")); QStringList resolutions; - for (auto resolution : supported_resolutions) + for (auto resolution : qAsConst(supported_resolutions)) resolutions << dpi_template.arg(resolution); QString dpi_text = dpi_combo->currentText(); @@ -920,9 +945,9 @@ void PrintWidget::updateColorMode() // slot void PrintWidget::resolutionEdited() { - QString resolution_text = dpi_combo->currentText(); - int index_of_space = resolution_text.indexOf(" "); - int dpi_value = resolution_text.left(index_of_space).toInt(); + auto resolution_text = dpi_combo->currentText(); + auto index_of_space = resolution_text.indexOf(QLatin1Char(' ')); + auto dpi_value = resolution_text.leftRef(index_of_space).toInt(); if (dpi_value > 0) map_printer->setResolution(dpi_value); } @@ -931,7 +956,7 @@ void PrintWidget::resolutionEdited() void PrintWidget::differentScaleClicked(bool checked) { if (!checked) - different_scale_edit->setValue(map->getScaleDenominator()); + different_scale_edit->setValue(int(map->getScaleDenominator())); different_scale_edit->setEnabled(checked); } @@ -939,12 +964,8 @@ void PrintWidget::differentScaleClicked(bool checked) // slot void PrintWidget::differentScaleEdited(int value) { - map_printer->setScale(value); - if (policy == SinglePage) - { - // Adjust the print area. - applyPrintAreaPolicy(); - } + map_printer->setScale(static_cast(value)); + applyPrintAreaPolicy(); if (different_scale_edit->value() < 500) { @@ -1075,22 +1096,22 @@ void PrintWidget::printClicked() void PrintWidget::exportToImage() { - static const QString filter_template("%1 (%2)"); - QStringList filters = { filter_template.arg(tr("PNG")).arg("*.png"), - filter_template.arg(tr("BMP")).arg("*.bmp"), - filter_template.arg(tr("TIFF")).arg("*.tif *.tiff"), - filter_template.arg(tr("JPEG")).arg("*.jpg *.jpeg"), + static const QString filter_template(QString::fromLatin1("%1 (%2)")); + QStringList filters = { filter_template.arg(tr("PNG"), QString::fromLatin1("*.png")), + filter_template.arg(tr("BMP"), QString::fromLatin1("*.bmp")), + filter_template.arg(tr("TIFF"), QString::fromLatin1("*.tif *.tiff")), + filter_template.arg(tr("JPEG"), QString::fromLatin1("*.jpg *.jpeg")), tr("All files (*.*)") }; - QString path = QFileDialog::getSaveFileName(this, tr("Export map ..."), {}, filters.join(";;")); + QString path = QFileDialog::getSaveFileName(this, tr("Export map ..."), {}, filters.join(QString::fromLatin1(";;"))); if (path.isEmpty()) return; - if (!path.endsWith(".png", Qt::CaseInsensitive) - && !path.endsWith(".bmp", Qt::CaseInsensitive) - && !path.endsWith(".tif", Qt::CaseInsensitive) && !path.endsWith(".tiff", Qt::CaseInsensitive) - && !path.endsWith(".jpg", Qt::CaseInsensitive) && !path.endsWith(".jpeg", Qt::CaseInsensitive) ) + if (!path.endsWith(QLatin1String(".png"), Qt::CaseInsensitive) + && !path.endsWith(QLatin1String(".bmp"), Qt::CaseInsensitive) + && !path.endsWith(QLatin1String(".tif"), Qt::CaseInsensitive) && !path.endsWith(QLatin1String(".tiff"), Qt::CaseInsensitive) + && !path.endsWith(QLatin1String(".jpg"), Qt::CaseInsensitive) && !path.endsWith(QLatin1String(".jpeg"), Qt::CaseInsensitive) ) { - path.append(".png"); + path.append(QString::fromLatin1(".png")); } qreal pixel_per_mm = map_printer->getOptions().resolution / 25.4; @@ -1142,17 +1163,17 @@ void PrintWidget::exportToPdf() printer->setCreator(main_window->appName()); printer->setDocName(QFileInfo(main_window->currentPath()).baseName()); - static const QString filter_template("%1 (%2)"); - QStringList filters = { filter_template.arg(tr("PDF")).arg("*.pdf"), + static const QString filter_template(QString::fromLatin1("%1 (%2)")); + QStringList filters = { filter_template.arg(tr("PDF"), QString::fromLatin1("*.pdf")), tr("All files (*.*)") }; - QString path = QFileDialog::getSaveFileName(this, tr("Export map ..."), {}, filters.join(";;")); + QString path = QFileDialog::getSaveFileName(this, tr("Export map ..."), {}, filters.join(QString::fromLatin1(";;"))); if (path.isEmpty()) { return; } - else if (!path.endsWith(".pdf", Qt::CaseInsensitive)) + else if (!path.endsWith(QLatin1String(".pdf"), Qt::CaseInsensitive)) { - path.append(".pdf"); + path.append(QLatin1String(".pdf")); } printer->setOutputFileName(path); diff --git a/src/gui/print_widget.h b/src/gui/print_widget.h index 2aa90510b..8c0d2afba 100644 --- a/src/gui/print_widget.h +++ b/src/gui/print_widget.h @@ -1,6 +1,6 @@ /* * Copyright 2012, 2013 Thomas Schöps - * Copyright 2012, 2013, 2014 Kai Pastor + * Copyright 2012-2016 Kai Pastor * * This file is part of OpenOrienteering. * @@ -21,8 +21,8 @@ #ifdef QT_PRINTSUPPORT_LIB -#ifndef _OPENORIENTEERING_PRINT_WIDGET_H_ -#define _OPENORIENTEERING_PRINT_WIDGET_H_ +#ifndef OPENORIENTEERING_PRINT_WIDGET_H +#define OPENORIENTEERING_PRINT_WIDGET_H #include #include @@ -72,13 +72,13 @@ Q_OBJECT Q_DECLARE_FLAGS(TaskFlags, TaskFlag) /** Constructs a new print widget. */ - PrintWidget(Map* map, MainWindow* main_window, MapView* main_view, MapEditorController* editor, QWidget* parent = NULL); + PrintWidget(Map* map, MainWindow* main_window, MapView* main_view, MapEditorController* editor, QWidget* parent = nullptr); /** Destroys the widget. */ - virtual ~PrintWidget(); + ~PrintWidget() override; /** Indicates the default widget size. */ - virtual QSize sizeHint() const; + QSize sizeHint() const override; /** Returns a translated name for the given paper size. */ static QString toString(QPrinter::PaperSize size); @@ -137,6 +137,9 @@ protected slots: /** This slot reacts to changes of the target combobox. */ void targetChanged(int index) const; + /** Opens a dialog to change printer properties. */ + void propertiesClicked(); + /** This slot reacts to changes of the paper size combobox. */ void paperSizeChanged(int index) const; @@ -261,6 +264,7 @@ protected slots: QDialogButtonBox* button_box; QComboBox* target_combo; + QToolButton* printer_properties_button; QComboBox* paper_size_combo; QWidget* page_orientation_widget; QButtonGroup* page_orientation_group; diff --git a/src/gui/select_crs_dialog.cpp b/src/gui/select_crs_dialog.cpp index baf51bc90..bac8deaba 100644 --- a/src/gui/select_crs_dialog.cpp +++ b/src/gui/select_crs_dialog.cpp @@ -123,11 +123,11 @@ void SelectCRSDialog::updateWidgets() { Georeferencing georef; auto spec = currentCRSSpec(); - auto valid = spec.isEmpty() || georef.setProjectedCRS("", spec); + auto valid = spec.isEmpty() || georef.setProjectedCRS({}, spec); button_box->button(QDialogButtonBox::Ok)->setEnabled(valid); if (valid) status_label->setText(tr("valid")); else - status_label->setText(QString("") % georef.getErrorText() % ""); + status_label->setText(QLatin1String("") + georef.getErrorText() + QLatin1String("")); } diff --git a/src/gui/settings_dialog.cpp b/src/gui/settings_dialog.cpp index afb9b6675..bc9de89e4 100644 --- a/src/gui/settings_dialog.cpp +++ b/src/gui/settings_dialog.cpp @@ -1,6 +1,6 @@ /* * Copyright 2012, 2013 Jan Dalheimer - * Copyright 2012-2015 Kai Pastor + * Copyright 2012-2016 Kai Pastor * * This file is part of OpenOrienteering. * @@ -19,53 +19,86 @@ */ #include "settings_dialog.h" -#include "settings_dialog_p.h" -#include -#include -#include -#include +#include +#include #include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include -#include -#include +#include +#include #include -#include "../settings.h" #include "../util.h" -#include "../util_gui.h" -#include "../util_translation.h" -#include "../util/scoped_signals_blocker.h" -#include "modifier_key.h" -#include "widgets/home_screen_widget.h" +#include "../util/backports.h" +#include "main_window.h" +#include "widgets/editor_settings_page.h" +#include "widgets/general_settings_page.h" +#ifdef MAPPER_USE_GDAL +# include "../gdal/gdal_settings_page.h" +#endif -// ### SettingsDialog ### SettingsDialog::SettingsDialog(QWidget* parent) - : QDialog(parent) + : QDialog { parent } + , tab_widget { nullptr } + , stack_widget { nullptr } { setWindowTitle(tr("Settings")); - QVBoxLayout* layout = new QVBoxLayout(); - this->setLayout(layout); + QVBoxLayout* layout = new QVBoxLayout(this); - tab_widget = new QTabWidget(); - layout->addWidget(tab_widget); + auto buttons = QDialogButtonBox::StandardButtons{ QDialogButtonBox::Ok }; + if (MainWindow::mobileMode()) + { + if (parent) + setGeometry(parent->geometry()); + + stack_widget = new QStackedWidget(); + layout->addWidget(stack_widget, 1); + + auto menu_widget = new QToolBar(); + menu_widget->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + menu_widget->setOrientation(Qt::Vertical); + stack_widget->addWidget(menu_widget); + } + else + { + buttons |= QDialogButtonBox::Reset | QDialogButtonBox::Cancel | QDialogButtonBox::Help; + + tab_widget = new QTabWidget(); +#ifndef Q_OS_OSX + tab_widget->setDocumentMode(true); +#endif + layout->addWidget(tab_widget, 1); + } - button_box = new QDialogButtonBox( - QDialogButtonBox::Ok | QDialogButtonBox::Apply | QDialogButtonBox::Cancel | QDialogButtonBox::Help, - Qt::Horizontal ); - layout->addWidget(button_box); + button_box = new QDialogButtonBox(buttons, Qt::Horizontal); connect(button_box, &QDialogButtonBox::clicked, this, &SettingsDialog::buttonPressed); + if (MainWindow::mobileMode()) + { + int left, top, right, bottom; + layout->getContentsMargins(&left, &top, &right, &bottom); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(0); + + QVBoxLayout* l = new QVBoxLayout(); + l->setContentsMargins(left, top, right, bottom); + l->addWidget(button_box); + layout->addLayout(l); + } + else + { + layout->addWidget(button_box); + } - // Add all pages - addPage(new GeneralPage(this)); - addPage(new EditorPage(this)); + addPages(); } SettingsDialog::~SettingsDialog() @@ -73,675 +106,115 @@ SettingsDialog::~SettingsDialog() // Nothing, not inlined. } -void SettingsDialog::addPage(SettingsPage* page) +void SettingsDialog::closeEvent(QCloseEvent* e) { - tab_widget->addTab(page, page->title()); + if (MainWindow::mobileMode()) + callOnAllPages(&SettingsPage::apply); + QDialog::closeEvent(e); } -void SettingsDialog::buttonPressed(QAbstractButton* button) +void SettingsDialog::keyPressEvent(QKeyEvent* event) { - QDialogButtonBox::StandardButton id = button_box->standardButton(button); - const int count = tab_widget->count(); - int i; - switch (id) + switch (event->key()) { - case QDialogButtonBox::Ok: - for (i = 0; i < count; i++) - static_cast< SettingsPage* >(tab_widget->widget(i))->ok(); - Settings::getInstance().applySettings(); - this->accept(); - break; - - case QDialogButtonBox::Apply: - for (i = 0; i < count; i++) - static_cast< SettingsPage* >(tab_widget->widget(i))->apply(); - Settings::getInstance().applySettings(); - break; - - case QDialogButtonBox::Cancel: - for (i = 0; i < count; i++) - static_cast< SettingsPage* >(tab_widget->widget(i))->cancel(); - this->reject(); - break; - - case QDialogButtonBox::Help: - Util::showHelp(this, QStringLiteral("settings.html")); + case Qt::Key_Back: + case Qt::Key_Escape: + if (MainWindow::mobileMode() && stack_widget->currentIndex() > 0) + { + stack_widget->setCurrentIndex(0); + auto buttons = button_box->standardButtons(); + button_box->setStandardButtons((buttons & ~QDialogButtonBox::Reset) | QDialogButtonBox::Help); + return; + } break; - default: - Q_UNREACHABLE(); - break; + ; // nothing } + QDialog::keyPressEvent(event); } - - -// ### SettingsPage ### - -SettingsPage::SettingsPage(QWidget* parent) - : QWidget(parent) -{ - // nothing -} - -void SettingsPage::cancel() -{ - changes.clear(); -} - -void SettingsPage::apply() -{ - QSettings settings; - for (int i = 0; i < changes.size(); i++) - settings.setValue(changes.keys().at(i), changes.values().at(i)); - changes.clear(); -} - -void SettingsPage::ok() -{ - this->apply(); -} - - - -// ### EditorPage ### - -EditorPage::EditorPage(QWidget* parent) - : SettingsPage(parent) -{ - QGridLayout* layout = new QGridLayout(); - this->setLayout(layout); - - int row = 0; - - antialiasing = new QCheckBox(tr("High quality map display (antialiasing)"), this); - antialiasing->setToolTip(tr("Antialiasing makes the map look much better, but also slows down the map display")); - layout->addWidget(antialiasing, row++, 0, 1, 2); - - text_antialiasing = new QCheckBox(tr("High quality text display in map (antialiasing), slow"), this); - text_antialiasing->setToolTip(tr("Antialiasing makes the map look much better, but also slows down the map display")); - layout->addWidget(text_antialiasing, row++, 0, 1, 2); - - QLabel* tolerance_label = new QLabel(tr("Click tolerance:")); - QSpinBox* tolerance = Util::SpinBox::create(0, 50, tr("mm", "millimeters")); - layout->addWidget(tolerance_label, row, 0); - layout->addWidget(tolerance, row++, 1); - - QLabel* snap_distance_label = new QLabel(tr("Snap distance (%1):").arg(ModifierKey::shift())); - QSpinBox* snap_distance = Util::SpinBox::create(0, 100, tr("mm", "millimeters")); - layout->addWidget(snap_distance_label, row, 0); - layout->addWidget(snap_distance, row++, 1); - - QLabel* fixed_angle_stepping_label = new QLabel(tr("Stepping of fixed angle mode (%1):").arg(ModifierKey::control())); - QSpinBox* fixed_angle_stepping = Util::SpinBox::create(1, 180, trUtf8("°", "Degree sign for angles")); - layout->addWidget(fixed_angle_stepping_label, row, 0); - layout->addWidget(fixed_angle_stepping, row++, 1); - - QCheckBox* select_symbol_of_objects = new QCheckBox(tr("When selecting an object, automatically select its symbol, too")); - layout->addWidget(select_symbol_of_objects, row++, 0, 1, 2); - - QCheckBox* zoom_out_away_from_cursor = new QCheckBox(tr("Zoom away from cursor when zooming out")); - layout->addWidget(zoom_out_away_from_cursor, row++, 0, 1, 2); - - QCheckBox* draw_last_point_on_right_click = new QCheckBox(tr("Drawing tools: set last point on finishing with right click")); - layout->addWidget(draw_last_point_on_right_click, row++, 0, 1, 2); - - QCheckBox* keep_settings_of_closed_templates = new QCheckBox(tr("Templates: keep settings of closed templates")); - layout->addWidget(keep_settings_of_closed_templates, row++, 0, 1, 2); - - - layout->setRowMinimumHeight(row++, 16); - layout->addWidget(Util::Headline::create(tr("Edit tool:")), row++, 0, 1, 2); - - edit_tool_delete_bezier_point_action = new QComboBox(); - edit_tool_delete_bezier_point_action->addItem(tr("Retain old shape"), (int)Settings::DeleteBezierPoint_RetainExistingShape); - edit_tool_delete_bezier_point_action->addItem(tr("Reset outer curve handles"), (int)Settings::DeleteBezierPoint_ResetHandles); - edit_tool_delete_bezier_point_action->addItem(tr("Keep outer curve handles"), (int)Settings::DeleteBezierPoint_KeepHandles); - layout->addWidget(new QLabel(tr("Action on deleting a curve point with %1:").arg(ModifierKey::control())), row, 0); - layout->addWidget(edit_tool_delete_bezier_point_action, row++, 1); - - edit_tool_delete_bezier_point_action_alternative = new QComboBox(); - edit_tool_delete_bezier_point_action_alternative->addItem(tr("Retain old shape"), (int)Settings::DeleteBezierPoint_RetainExistingShape); - edit_tool_delete_bezier_point_action_alternative->addItem(tr("Reset outer curve handles"), (int)Settings::DeleteBezierPoint_ResetHandles); - edit_tool_delete_bezier_point_action_alternative->addItem(tr("Keep outer curve handles"), (int)Settings::DeleteBezierPoint_KeepHandles); - layout->addWidget(new QLabel(tr("Action on deleting a curve point with %1:").arg(ModifierKey::controlShift())), row, 0); - layout->addWidget(edit_tool_delete_bezier_point_action_alternative, row++, 1); - - layout->setRowMinimumHeight(row++, 16); - layout->addWidget(Util::Headline::create(tr("Rectangle tool:")), row++, 0, 1, 2); - - QLabel* rectangle_helper_cross_radius_label = new QLabel(tr("Radius of helper cross:")); - QSpinBox* rectangle_helper_cross_radius = Util::SpinBox::create(0, 999999, tr("mm", "millimeters")); - layout->addWidget(rectangle_helper_cross_radius_label, row, 0); - layout->addWidget(rectangle_helper_cross_radius, row++, 1); - - QCheckBox* rectangle_preview_line_width = new QCheckBox(tr("Preview the width of lines with helper cross")); - layout->addWidget(rectangle_preview_line_width, row++, 0, 1, 2); - - - antialiasing->setChecked(Settings::getInstance().getSetting(Settings::MapDisplay_Antialiasing).toBool()); - text_antialiasing->setChecked(Settings::getInstance().getSetting(Settings::MapDisplay_TextAntialiasing).toBool()); - tolerance->setValue(Settings::getInstance().getSetting(Settings::MapEditor_ClickToleranceMM).toInt()); - snap_distance->setValue(Settings::getInstance().getSetting(Settings::MapEditor_SnapDistanceMM).toInt()); - fixed_angle_stepping->setValue(Settings::getInstance().getSetting(Settings::MapEditor_FixedAngleStepping).toInt()); - select_symbol_of_objects->setChecked(Settings::getInstance().getSetting(Settings::MapEditor_ChangeSymbolWhenSelecting).toBool()); - zoom_out_away_from_cursor->setChecked(Settings::getInstance().getSetting(Settings::MapEditor_ZoomOutAwayFromCursor).toBool()); - draw_last_point_on_right_click->setChecked(Settings::getInstance().getSetting(Settings::MapEditor_DrawLastPointOnRightClick).toBool()); - keep_settings_of_closed_templates->setChecked(Settings::getInstance().getSetting(Settings::Templates_KeepSettingsOfClosed).toBool()); - - edit_tool_delete_bezier_point_action->setCurrentIndex(edit_tool_delete_bezier_point_action->findData(Settings::getInstance().getSetting(Settings::EditTool_DeleteBezierPointAction).toInt())); - edit_tool_delete_bezier_point_action_alternative->setCurrentIndex(edit_tool_delete_bezier_point_action_alternative->findData(Settings::getInstance().getSetting(Settings::EditTool_DeleteBezierPointActionAlternative).toInt())); - - rectangle_helper_cross_radius->setValue(Settings::getInstance().getSetting(Settings::RectangleTool_HelperCrossRadiusMM).toInt()); - rectangle_preview_line_width->setChecked(Settings::getInstance().getSetting(Settings::RectangleTool_PreviewLineWidth).toBool()); - - layout->setRowStretch(row, 1); - - updateWidgets(); - - connect(antialiasing, &QAbstractButton::toggled, this, &EditorPage::antialiasingClicked); - connect(text_antialiasing, &QAbstractButton::toggled, this, &EditorPage::textAntialiasingClicked); - connect(tolerance, static_cast(&QSpinBox::valueChanged), this, &EditorPage::toleranceChanged); - connect(snap_distance, static_cast(&QSpinBox::valueChanged), this, &EditorPage::snapDistanceChanged); - connect(fixed_angle_stepping, static_cast(&QSpinBox::valueChanged), this, &EditorPage::fixedAngleSteppingChanged); - connect(select_symbol_of_objects, &QAbstractButton::clicked, this, &EditorPage::selectSymbolOfObjectsClicked); - connect(zoom_out_away_from_cursor, &QAbstractButton::clicked, this, &EditorPage::zoomOutAwayFromCursorClicked); - connect(draw_last_point_on_right_click, &QAbstractButton::clicked, this, &EditorPage::drawLastPointOnRightClickClicked); - connect(keep_settings_of_closed_templates, &QAbstractButton::clicked, this, &EditorPage::keepSettingsOfClosedTemplatesClicked); - - connect(edit_tool_delete_bezier_point_action, static_cast(&QComboBox::currentIndexChanged), this, &EditorPage::editToolDeleteBezierPointActionChanged); - connect(edit_tool_delete_bezier_point_action_alternative, static_cast(&QComboBox::currentIndexChanged), this, &EditorPage::editToolDeleteBezierPointActionAlternativeChanged); - - connect(rectangle_helper_cross_radius, static_cast(&QSpinBox::valueChanged), this, &EditorPage::rectangleHelperCrossRadiusChanged); - connect(rectangle_preview_line_width, &QAbstractButton::clicked, this, &EditorPage::rectanglePreviewLineWidthChanged); -} - -QString EditorPage::title() const -{ - return tr("Editor"); -} - -void EditorPage::updateWidgets() -{ - text_antialiasing->setEnabled(antialiasing->isChecked()); -} - -void EditorPage::antialiasingClicked(bool checked) -{ - changes.insert(Settings::getInstance().getSettingPath(Settings::MapDisplay_Antialiasing), QVariant(checked)); - updateWidgets(); -} - -void EditorPage::textAntialiasingClicked(bool checked) -{ - changes.insert(Settings::getInstance().getSettingPath(Settings::MapDisplay_TextAntialiasing), QVariant(checked)); -} - -void EditorPage::toleranceChanged(int value) -{ - changes.insert(Settings::getInstance().getSettingPath(Settings::MapEditor_ClickToleranceMM), QVariant(value)); -} - -void EditorPage::snapDistanceChanged(int value) -{ - changes.insert(Settings::getInstance().getSettingPath(Settings::MapEditor_SnapDistanceMM), QVariant(value)); -} - -void EditorPage::fixedAngleSteppingChanged(int value) -{ - changes.insert(Settings::getInstance().getSettingPath(Settings::MapEditor_FixedAngleStepping), QVariant(value)); -} - -void EditorPage::selectSymbolOfObjectsClicked(bool checked) -{ - changes.insert(Settings::getInstance().getSettingPath(Settings::MapEditor_ChangeSymbolWhenSelecting), QVariant(checked)); -} - -void EditorPage::zoomOutAwayFromCursorClicked(bool checked) -{ - changes.insert(Settings::getInstance().getSettingPath(Settings::MapEditor_ZoomOutAwayFromCursor), QVariant(checked)); -} - -void EditorPage::drawLastPointOnRightClickClicked(bool checked) -{ - changes.insert(Settings::getInstance().getSettingPath(Settings::MapEditor_DrawLastPointOnRightClick), QVariant(checked)); -} - -void EditorPage::keepSettingsOfClosedTemplatesClicked(bool checked) -{ - changes.insert(Settings::getInstance().getSettingPath(Settings::Templates_KeepSettingsOfClosed), QVariant(checked)); -} - -void EditorPage::editToolDeleteBezierPointActionChanged(int index) -{ - changes.insert(Settings::getInstance().getSettingPath(Settings::EditTool_DeleteBezierPointAction), edit_tool_delete_bezier_point_action->itemData(index)); -} - -void EditorPage::editToolDeleteBezierPointActionAlternativeChanged(int index) -{ - changes.insert(Settings::getInstance().getSettingPath(Settings::EditTool_DeleteBezierPointActionAlternative), edit_tool_delete_bezier_point_action_alternative->itemData(index)); -} - -void EditorPage::rectangleHelperCrossRadiusChanged(int value) -{ - changes.insert(Settings::getInstance().getSettingPath(Settings::RectangleTool_HelperCrossRadiusMM), QVariant(value)); -} - -void EditorPage::rectanglePreviewLineWidthChanged(bool checked) -{ - changes.insert(Settings::getInstance().getSettingPath(Settings::RectangleTool_PreviewLineWidth), QVariant(checked)); -} - - - -// ### GeneralPage ### - -const int GeneralPage::TranslationFromFile = -1; - -GeneralPage::GeneralPage(QWidget* parent) - : SettingsPage(parent) +void SettingsDialog::addPages() { - QGridLayout* layout = new QGridLayout(); - setLayout(layout); - - int row = 0; - layout->addWidget(Util::Headline::create(tr("Appearance")), row, 1, 1, 2); - - row++; - QLabel* language_label = new QLabel(tr("Language:")); - layout->addWidget(language_label, row, 1); - - language_box = new QComboBox(this); - updateLanguageBox(); - layout->addWidget(language_box, row, 2); - - QAbstractButton* language_file_button = new QToolButton(); - language_file_button->setIcon(QIcon(QStringLiteral(":/images/open.png"))); - layout->addWidget(language_file_button, row, 3); - - row++; - layout->addItem(Util::SpacerItem::create(this), row, 1); - - row++; - layout->addWidget(Util::Headline::create(tr("Screen")), row, 1, 1, 2); - - row++; - QLabel* ppi_label = new QLabel(tr("Pixels per inch:")); - layout->addWidget(ppi_label, row, 1); - - ppi_edit = Util::SpinBox::create(2, 0.01, 9999); - ppi_edit->setValue(Settings::getInstance().getSetting(Settings::General_PixelsPerInch).toFloat()); - layout->addWidget(ppi_edit, row, 2); - - QAbstractButton* ppi_calculate_button = new QToolButton(); - ppi_calculate_button->setIcon(QIcon(QStringLiteral(":/images/settings.png"))); - layout->addWidget(ppi_calculate_button, row, 3); - - row++; - layout->addItem(Util::SpacerItem::create(this), row, 1); - - row++; - layout->addWidget(Util::Headline::create(tr("Program start")), row, 1, 1, 2); - - row++; - QCheckBox* open_mru_check = new QCheckBox(AbstractHomeScreenWidget::tr("Open most recently used file")); - open_mru_check->setChecked(Settings::getInstance().getSetting(Settings::General_OpenMRUFile).toBool()); - layout->addWidget(open_mru_check, row, 1, 1, 2); - - row++; - QCheckBox* tips_visible_check = new QCheckBox(AbstractHomeScreenWidget::tr("Show tip of the day")); - tips_visible_check->setChecked(Settings::getInstance().getSetting(Settings::HomeScreen_TipsVisible).toBool()); - layout->addWidget(tips_visible_check, row, 1, 1, 2); - - row++; - layout->addItem(Util::SpacerItem::create(this), row, 1); - - row++; - layout->addWidget(Util::Headline::create(tr("Saving files")), row, 1, 1, 2); - - row++; - QCheckBox* compatibility_check = new QCheckBox(tr("Retain compatibility with Mapper %1").arg(QStringLiteral("0.5"))); - compatibility_check->setChecked(Settings::getInstance().getSetting(Settings::General_RetainCompatiblity).toBool()); - layout->addWidget(compatibility_check, row, 1, 1, 2); - - // Possible point: limit size of undo/redo journal - - int autosave_interval = Settings::getInstance().getSetting(Settings::General_AutosaveInterval).toInt(); - - row++; - QCheckBox* autosave_check = new QCheckBox(tr("Save information for automatic recovery")); - autosave_check->setChecked(autosave_interval > 0); - layout->addWidget(autosave_check, row, 1, 1, 2); - - row++; - autosave_interval_label = new QLabel(tr("Recovery information saving interval:")); - layout->addWidget(autosave_interval_label, row, 1); - - autosave_interval_edit = Util::SpinBox::create(1, 120, tr("min", "unit minutes"), 1); - autosave_interval_edit->setValue(qAbs(autosave_interval)); - autosave_interval_edit->setEnabled(autosave_interval > 0); - layout->addWidget(autosave_interval_edit, row, 2); - - row++; - layout->addItem(Util::SpacerItem::create(this), row, 1); - - row++; - layout->addWidget(Util::Headline::create(tr("File import and export")), row, 1, 1, 2); - - row++; - QLabel* encoding_label = new QLabel(tr("8-bit encoding:")); - layout->addWidget(encoding_label, row, 1); - - encoding_box = new QComboBox(); - encoding_box->addItem(QStringLiteral("System")); - encoding_box->addItem(QStringLiteral("Windows-1250")); - encoding_box->addItem(QStringLiteral("Windows-1252")); - encoding_box->addItem(QStringLiteral("ISO-8859-1")); - encoding_box->addItem(QStringLiteral("ISO-8859-15")); - encoding_box->setEditable(true); - QStringList availableCodecs; - for (const QByteArray& item : QTextCodec::availableCodecs()) - { - availableCodecs.append(QString::fromUtf8(item)); - } - if (!availableCodecs.empty()) - { - availableCodecs.sort(Qt::CaseInsensitive); - availableCodecs.removeDuplicates(); - encoding_box->addItem(tr("More...")); - } - QCompleter* completer = new QCompleter(availableCodecs, this); - completer->setCaseSensitivity(Qt::CaseInsensitive); - encoding_box->setCompleter(completer); - encoding_box->setCurrentText(Settings::getInstance().getSetting(Settings::General_Local8BitEncoding).toString()); - layout->addWidget(encoding_box, row, 2); - - row++; - QCheckBox* ocd_importer_check = new QCheckBox(tr("Use the new OCD importer also for version 8 files")); - ocd_importer_check->setChecked(Settings::getInstance().getSetting(Settings::General_NewOcd8Implementation).toBool()); - layout->addWidget(ocd_importer_check, row, 1, 1, 2); - - row++; - layout->setRowStretch(row, 1); - -#if defined(Q_OS_MAC) - // Center setting items - layout->setColumnStretch(0, 2); + addPage(new GeneralSettingsPage(this)); + addPage(new EditorSettingsPage(this)); +#ifdef MAPPER_USE_GDAL + addPage(new GdalSettingsPage(this)); #endif - layout->setColumnStretch(2, 1); - layout->setColumnStretch(2, 2); - layout->setColumnStretch(layout->columnCount(), 2); - - connect(language_box, static_cast(&QComboBox::currentIndexChanged), this, &GeneralPage::languageChanged); - connect(language_file_button, &QAbstractButton::clicked, this, &GeneralPage::openTranslationFileDialog); - connect(ppi_edit, static_cast(&QDoubleSpinBox::valueChanged), this, &GeneralPage::ppiChanged); - connect(ppi_calculate_button, &QAbstractButton::clicked, this, &GeneralPage::openPPICalculationDialog); - connect(open_mru_check, &QAbstractButton::clicked, this, &GeneralPage::openMRUFileClicked); - connect(tips_visible_check, &QAbstractButton::clicked, this, &GeneralPage::tipsVisibleClicked); - connect(encoding_box, &QComboBox::currentTextChanged, this, &GeneralPage::encodingChanged); - connect(ocd_importer_check, &QAbstractButton::clicked, this, &GeneralPage::ocdImporterClicked); - connect(autosave_check, &QAbstractButton::clicked, this, &GeneralPage::autosaveChanged); - connect(autosave_interval_edit, static_cast(&QSpinBox::valueChanged), this, &GeneralPage::autosaveIntervalChanged); - connect(compatibility_check, &QAbstractButton::clicked, this, &GeneralPage::retainCompatibilityChanged); -} - -QString GeneralPage::title() const -{ - return tr("General"); } -void GeneralPage::apply() +void SettingsDialog::addPage(SettingsPage* page) { - const Settings& settings = Settings::getInstance(); - const QString translation_file_key(settings.getSettingPath(Settings::General_TranslationFile)); - const QString language_key(settings.getSettingPath(Settings::General_Language)); - - if (changes.contains(language_key) || changes.contains(translation_file_key)) + if (MainWindow::mobileMode()) { - if (!changes.contains(translation_file_key)) + if (auto form_layout = qobject_cast(page->layout())) { - // Set an empty file name when changing the language without setting a filename. - changes[translation_file_key] = QString(); + form_layout->setRowWrapPolicy(QFormLayout::WrapAllRows); + auto labels = page->findChildren(); + for (auto label : qAsConst(labels)) + label->setWordWrap(true); } + page->setMaximumWidth(width()); - QVariant lang = changes.contains(language_key) ? changes[language_key] : settings.getSetting(Settings::General_Language); - QVariant translation_file = changes[translation_file_key]; - if ( settings.getSetting(Settings::General_Language) != lang || - settings.getSetting(Settings::General_TranslationFile) != translation_file ) + auto scrollarea = new QScrollArea(); + scrollarea->setFrameShape(QFrame::NoFrame); + QScroller::grabGesture(scrollarea, QScroller::TouchGesture); + scrollarea->setWidget(page); + stack_widget->addWidget(scrollarea); + + auto menu_widget = qobject_cast(stack_widget->widget(0)); + auto action = menu_widget->addAction(page->title()); + connect(action, &QAction::triggered, [this, scrollarea]() { - qApp->installEventFilter(this); - // Show an message box in the new language. - TranslationUtil translation((QLocale::Language)lang.toInt(), translation_file.toString()); - qApp->installTranslator(&translation.getQtTranslator()); - qApp->installTranslator(&translation.getAppTranslator()); - if (lang.toInt() <= 1 || lang.toInt() == 31) // cf. QLocale::Language - { - QMessageBox::information(window(), QStringLiteral("Notice"), QStringLiteral("The program must be restarted for the language change to take effect!")); - } - else - { - QMessageBox::information(window(), tr("Notice"), tr("The program must be restarted for the language change to take effect!")); - } - qApp->removeTranslator(&translation.getAppTranslator()); - qApp->removeTranslator(&translation.getQtTranslator()); - qApp->removeEventFilter(this); - -#if defined(Q_OS_MAC) - // The native [file] dialogs will use the first element of the - // AppleLanguages array in the application's .plist file - - // and this file is also the one used by QSettings. - const QString mapper_language(translation.getLocale().name().left(2)); - changes["AppleLanguages"] = ( QStringList() << mapper_language ); -#endif - } - } - SettingsPage::apply(); -} - -bool GeneralPage::eventFilter(QObject* /* watched */, QEvent* event) -{ - if (event->type() == QEvent::LanguageChange) - return true; - - return false; -} - -void GeneralPage::languageChanged(int index) -{ - if (language_box->itemData(index) == TranslationFromFile) - { - openTranslationFileDialog(); + stack_widget->setCurrentWidget(scrollarea); + scrollarea->ensureVisible(0, 0); + button_box->setStandardButtons(button_box->standardButtons() | QDialogButtonBox::Reset); + } ); } else { - changes.insert(Settings::getInstance().getSettingPath(Settings::General_Language), language_box->itemData(index).toInt()); - } -} - -void GeneralPage::updateLanguageBox() -{ - const Settings& settings = Settings::getInstance(); - const QString translation_file_key(settings.getSettingPath(Settings::General_TranslationFile)); - const QString language_key(settings.getSettingPath(Settings::General_Language)); - - LanguageCollection language_map = TranslationUtil::getAvailableLanguages(); - - // Add the locale of the explicit translation file - QString translation_file; - if (changes.contains(translation_file_key)) - translation_file = changes[translation_file_key].toString(); - else - translation_file = settings.getSetting(Settings::General_TranslationFile).toString(); - - QString locale_name = TranslationUtil::localeNameForFile(translation_file); - if (!locale_name.isEmpty()) - { - QLocale file_locale(locale_name); - QString language_name = file_locale.nativeLanguageName(); - if (!language_map.contains(language_name)) - language_map.insert(language_name, file_locale.language()); - } - - // Update the language box - const QSignalBlocker block(language_box); - language_box->clear(); - - LanguageCollection::const_iterator end = language_map.constEnd(); - for (LanguageCollection::const_iterator it = language_map.constBegin(); it != end; ++it) - language_box->addItem(it.key(), (int)it.value()); - language_box->addItem(tr("Use translation file..."), TranslationFromFile); - - // Select current language - int index = language_box->findData(changes.contains(language_key) ? - changes[language_key].toInt() : - settings.getSetting(Settings::General_Language).toInt() ); - - if (index < 0) - index = language_box->findData((int)QLocale::English); - language_box->setCurrentIndex(index); -} - -void GeneralPage::openMRUFileClicked(bool state) -{ - changes.insert(Settings::getInstance().getSettingPath(Settings::General_OpenMRUFile), state); -} - -void GeneralPage::tipsVisibleClicked(bool state) -{ - changes.insert(Settings::getInstance().getSettingPath(Settings::HomeScreen_TipsVisible), state); -} - -// slot -void GeneralPage::encodingChanged(const QString& name) -{ - const QSignalBlocker block(encoding_box); - - if (name == tr("More...")) - { - encoding_box->setCurrentText(QString()); - encoding_box->completer()->setCompletionPrefix(QString()); - encoding_box->completer()->complete(); - return; - } - - QTextCodec* codec = (name == QStringLiteral("System")) - ? QTextCodec::codecForLocale() - : QTextCodec::codecForName(name.toLatin1()); - if (codec) - { - changes.insert(Settings::getInstance().getSettingPath(Settings::General_Local8BitEncoding), name.toUtf8()); - encoding_box->setCurrentText(name); + tab_widget->addTab(page, page->title()); } } -// slot -void GeneralPage::ocdImporterClicked(bool state) +void SettingsDialog::callOnAllPages(void (SettingsPage::*member)()) { - changes.insert(Settings::getInstance().getSettingPath(Settings::General_NewOcd8Implementation), state); + auto pages = MainWindow::mobileMode() ? stack_widget->findChildren() + : tab_widget->findChildren(); + for (auto page : qAsConst(pages)) + (page->*member)(); } -void GeneralPage::openTranslationFileDialog() +void SettingsDialog::buttonPressed(QAbstractButton* button) { - Settings& settings = Settings::getInstance(); - const QString translation_file_key(settings.getSettingPath(Settings::General_TranslationFile)); - const QString language_key(settings.getSettingPath(Settings::General_Language)); - - QString current_filename(settings.getSetting(Settings::General_Language).toString()); - if (changes.contains(translation_file_key)) - current_filename = changes[translation_file_key].toString(); - - QString filename = QFileDialog::getOpenFileName(this, - tr("Open translation"), current_filename, tr("Translation files (*.qm)")); - if (!filename.isNull()) + QDialogButtonBox::StandardButton id = button_box->standardButton(button); + switch (id) { - QString locale_name(TranslationUtil::localeNameForFile(filename)); - if (locale_name.isEmpty()) + case QDialogButtonBox::Ok: + callOnAllPages(&SettingsPage::apply); + if (MainWindow::mobileMode() && stack_widget->currentIndex() > 0) { - QMessageBox::critical(this, tr("Open translation"), - tr("The selected file is not a valid translation.") ); + stack_widget->setCurrentIndex(0); + button_box->setStandardButtons(button_box->standardButtons() & ~QDialogButtonBox::Reset); } else { - QLocale locale(locale_name); - changes.insert(translation_file_key, filename); - changes.insert(language_key, locale.language()); + this->accept(); } - } - updateLanguageBox(); -} - -void GeneralPage::autosaveChanged(bool state) -{ - autosave_interval_label->setEnabled(state); - autosave_interval_edit->setEnabled(state); - - int interval = autosave_interval_edit->value(); - if (!state) - interval = -interval; - changes.insert(Settings::getInstance().getSettingPath(Settings::General_AutosaveInterval), interval); -} - -void GeneralPage::autosaveIntervalChanged(int value) -{ - changes.insert(Settings::getInstance().getSettingPath(Settings::General_AutosaveInterval), value); -} - -void GeneralPage::retainCompatibilityChanged(bool state) -{ - changes.insert(Settings::getInstance().getSettingPath(Settings::General_RetainCompatiblity), state); -} - -void GeneralPage::ppiChanged(double ppi) -{ - changes.insert(Settings::getInstance().getSettingPath(Settings::General_PixelsPerInch), QVariant(ppi)); -} - -void GeneralPage::openPPICalculationDialog() -{ - int primary_screen_width = QApplication::primaryScreen()->size().width(); - int primary_screen_height = QApplication::primaryScreen()->size().height(); - float screen_diagonal_pixels = qSqrt(primary_screen_width*primary_screen_width + primary_screen_height*primary_screen_height); - - float old_ppi = ppi_edit->value(); - float old_screen_diagonal_inches = screen_diagonal_pixels / old_ppi; - - QDialog* dialog = new QDialog(window(), Qt::WindowSystemMenuHint | Qt::WindowTitleHint); - - QGridLayout* layout = new QGridLayout(); - - int row = 0; - QLabel* resolution_label = new QLabel(tr("Primary screen resolution in pixels:")); - layout->addWidget(resolution_label, row, 0); - - - QLabel* resolution_display = new QLabel(QStringLiteral("%1 x %2").arg(primary_screen_width).arg(primary_screen_height)); - layout->addWidget(resolution_display, row, 1); - - row++; - QLabel* size_label = new QLabel(tr("Primary screen size in inches (diagonal):")); - layout->addWidget(size_label, row, 0); - - QDoubleSpinBox* size_edit = Util::SpinBox::create(2, 0.01, 9999); - size_edit->setValue(old_screen_diagonal_inches); - layout->addWidget(size_edit, row, 1); - - row++; - layout->addItem(Util::SpacerItem::create(this), row, 1); - - row++; - QDialogButtonBox* button_box = new QDialogButtonBox(QDialogButtonBox::Cancel | QDialogButtonBox::Ok); - layout->addWidget(button_box, row, 0, 1, 2); - - dialog->setLayout(layout); - connect(button_box, &QDialogButtonBox::accepted, dialog, &QDialog::accept); - connect(button_box, &QDialogButtonBox::rejected, dialog, &QDialog::reject); - dialog->exec(); - - if (dialog->result() == QDialog::Accepted) - { - float screen_diagonal_inches = size_edit->value(); - float new_ppi = screen_diagonal_pixels / screen_diagonal_inches; - ppi_edit->setValue(new_ppi); - ppiChanged(new_ppi); + break; + + case QDialogButtonBox::Reset: + callOnAllPages(&SettingsPage::reset); + break; + + case QDialogButtonBox::Cancel: + this->reject(); + break; + + case QDialogButtonBox::Help: + Util::showHelp(this, QLatin1String("settings.html")); + break; + + default: + qDebug("%s: Unexpected button '0x%x'", Q_FUNC_INFO, id); } } diff --git a/src/gui/settings_dialog.h b/src/gui/settings_dialog.h index 3fd5ffe6f..8372080bd 100644 --- a/src/gui/settings_dialog.h +++ b/src/gui/settings_dialog.h @@ -1,6 +1,6 @@ /* * Copyright 2012, 2013 Jan Dalheimer - * Copyright 2013, 2015 Kai Pastor + * Copyright 2013-2016 Kai Pastor * * This file is part of OpenOrienteering. * @@ -18,43 +18,81 @@ * along with OpenOrienteering. If not, see . */ -#ifndef _OPENORIENTEERING_SETTINGS_DIALOG_H_ -#define _OPENORIENTEERING_SETTINGS_DIALOG_H_ +#ifndef OPENORIENTEERING_SETTINGS_DIALOG_H +#define OPENORIENTEERING_SETTINGS_DIALOG_H #include QT_BEGIN_NAMESPACE -class QTabWidget; class QAbstractButton; class QDialogButtonBox; +class QStackedWidget; +class QTabWidget; QT_END_NAMESPACE class SettingsPage; - -/** A dialog for editing Mapper's settings. */ +/** + * A dialog for editing Mapper's settings. + */ class SettingsDialog : public QDialog { Q_OBJECT public: - /** Constructs a new settings dialog. */ + /** + * Constructs a new settings dialog. + */ explicit SettingsDialog(QWidget* parent = nullptr); - /** Destroys the settings dialog. */ - virtual ~SettingsDialog(); + /** + * Destroys the settings dialog. + */ + ~SettingsDialog() override; + +protected: + /** + * Adds all known pages to the dialog. + * + * This function is called from the constructor. It may be overridden to + * provide dialogs with different pages. + */ + virtual void addPages(); + + /** + * Adds a single page to the dialog. + */ + void addPage(SettingsPage* page); + + /** + * Calls a SettingsPage member function on all pages. + */ + void callOnAllPages(void (SettingsPage::*member)()); + + + void closeEvent(QCloseEvent* event) override; + + void keyPressEvent(QKeyEvent* event) override; private slots: - /** Reacts to button presses (Ok, Cancel, Apply[?]) */ + /** + * Reacts to dialog buttons (OK, Cancel, Rest). + */ void buttonPressed(QAbstractButton* button); private: - /** Adds a page to the dialog. */ - void addPage(SettingsPage* page); - - /** A tab widget which holds all pages. */ + /** + * A tab widget which holds all pages in desktop mode. + */ QTabWidget* tab_widget; - /** The box of dialog buttons. */ + /** + * A stack widget which holds all pages in mobile mode. + */ + QStackedWidget* stack_widget; + + /** + * The box of standard dialog buttons. + */ QDialogButtonBox* button_box; }; diff --git a/src/gui/settings_dialog_p.h b/src/gui/settings_dialog_p.h deleted file mode 100644 index 0265f7bbc..000000000 --- a/src/gui/settings_dialog_p.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2012, 2013 Jan Dalheimer - * Copyright 2013-2015 Kai Pastor - * - * This file is part of OpenOrienteering. - * - * OpenOrienteering 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. - * - * OpenOrienteering 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 OpenOrienteering. If not, see . - */ - -#ifndef _OPENORIENTEERING_SETTINGS_DIALOG_PRIVATE_H_ -#define _OPENORIENTEERING_SETTINGS_DIALOG_PRIVATE_H_ - -#include -#include - -class QCheckBox; -class QComboBox; -class QLabel; -class QDoubleSpinBox; -class QSpinBox; - -class MainWindow; - - -class SettingsPage : public QWidget -{ -Q_OBJECT -public: - explicit SettingsPage(QWidget* parent = nullptr); - virtual QString title() const = 0; - virtual void cancel(); - virtual void apply(); - virtual void ok(); - -protected: - // The changes to be done when accepted - QHash changes; -}; - - - -class EditorPage : public SettingsPage -{ -Q_OBJECT -public: - explicit EditorPage(QWidget* parent = nullptr); - QString title() const override; - -private slots: - void antialiasingClicked(bool checked); - void textAntialiasingClicked(bool checked); - void toleranceChanged(int value); - void snapDistanceChanged(int value); - void fixedAngleSteppingChanged(int value); - void selectSymbolOfObjectsClicked(bool checked); - void zoomOutAwayFromCursorClicked(bool checked); - void drawLastPointOnRightClickClicked(bool checked); - - void editToolDeleteBezierPointActionChanged(int index); - void editToolDeleteBezierPointActionAlternativeChanged(int index); - - void rectangleHelperCrossRadiusChanged(int value); - void rectanglePreviewLineWidthChanged(bool checked); - - void keepSettingsOfClosedTemplatesClicked(bool checked); - -private: - void updateWidgets(); - - QCheckBox* antialiasing; - QCheckBox* text_antialiasing; - QComboBox* edit_tool_delete_bezier_point_action; - QComboBox* edit_tool_delete_bezier_point_action_alternative; -}; - - - -class GeneralPage : public SettingsPage -{ -Q_OBJECT -public: - explicit GeneralPage(QWidget* parent = nullptr); - QString title() const override; - void apply() override; - -protected: - /** This event filter stops LanguageChange events. */ - bool eventFilter(QObject* watched, QEvent* event) override; - -private slots: - void languageChanged(int index); - - void openMRUFileClicked(bool state); - - void tipsVisibleClicked(bool state); - - void openTranslationFileDialog(); - - void ppiChanged(double ppi); - - void openPPICalculationDialog(); - - void encodingChanged(const QString& name); - - void ocdImporterClicked(bool state); - - void autosaveChanged(bool state); - - void autosaveIntervalChanged(int value); - - void retainCompatibilityChanged(bool state); - -private: - /** Adds the available languages to the language combo box, - * and sets the current element. - */ - void updateLanguageBox(); - - QComboBox* language_box; - const static int TranslationFromFile; - - QDoubleSpinBox* ppi_edit; - - QComboBox* encoding_box; - - QLabel* autosave_interval_label; - QSpinBox* autosave_interval_edit; -}; - -#endif diff --git a/src/gui/text_browser_dialog.cpp b/src/gui/text_browser_dialog.cpp index cff978d1f..5ee53250d 100644 --- a/src/gui/text_browser_dialog.cpp +++ b/src/gui/text_browser_dialog.cpp @@ -61,7 +61,7 @@ TextBrowserDialog::TextBrowserDialog(const QUrl& initial_url, QWidget* parent) buttons_layout->addStretch(1); - QPushButton* close_button = new QPushButton(QApplication::translate("QDialogButtonBox", "&Close")); + QPushButton* close_button = new QPushButton(QApplication::translate("QPlatformTheme", "Close")); close_button->setDefault(true); buttons_layout->addWidget(close_button); diff --git a/src/gui/widgets/action_grid_bar.cpp b/src/gui/widgets/action_grid_bar.cpp index e9a97c706..100c1f567 100644 --- a/src/gui/widgets/action_grid_bar.cpp +++ b/src/gui/widgets/action_grid_bar.cpp @@ -50,7 +50,7 @@ ActionGridBar::ActionGridBar(Direction direction, int rows, QWidget* parent) setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); // Create overflow action - overflow_action = new QAction(QIcon(":/images/three-dots.png"), tr("Show remaining items"), this); + overflow_action = new QAction(QIcon(QString::fromLatin1(":/images/three-dots.png")), tr("Show remaining items"), this); connect(overflow_action, SIGNAL(triggered()), this, SLOT(overflowActionClicked())); overflow_button = NULL; overflow_menu = new QMenu(this); diff --git a/src/gui/widgets/crs_param_widgets.cpp b/src/gui/widgets/crs_param_widgets.cpp index 511bd940d..dca1634be 100644 --- a/src/gui/widgets/crs_param_widgets.cpp +++ b/src/gui/widgets/crs_param_widgets.cpp @@ -37,16 +37,16 @@ UTMZoneEdit::UTMZoneEdit(CRSParameterWidgetObserver& observer, QWidget* parent) : QWidget(parent) , observer(observer) { - static const QRegExp zone_regexp("(?:[0-5]?[1-9]|[1-6]0)(?: [NS])?"); + static const QRegExp zone_regexp(QString::fromLatin1("(?:[0-5]?[1-9]|[1-6]0)(?: [NS])?")); static QStringList zone_list; if (zone_list.isEmpty()) { for (int i = 1; i <= 60; ++i) { QString zone = QString::number(i); - zone_list << QString("%1 N").arg(zone) << QString("%1 S").arg(zone); + zone_list << QString::fromLatin1("%1 N").arg(zone) << QString::fromLatin1("%1 S").arg(zone); if (i < 10) - zone_list << QString("0%1 N").arg(zone) << QString("0%1 S").arg(zone); + zone_list << QString::fromLatin1("0%1 N").arg(zone) << QString::fromLatin1("0%1 S").arg(zone); } } diff --git a/src/gui/widgets/crs_selector.cpp b/src/gui/widgets/crs_selector.cpp index 980b32988..7078c5f92 100644 --- a/src/gui/widgets/crs_selector.cpp +++ b/src/gui/widgets/crs_selector.cpp @@ -290,7 +290,7 @@ void CRSSelector::addParameterFields(const CRSTemplate* crs) auto field = parameter->createEditor(*this); setParameterWidget(field, true); setParameterKey(field, parameter->id()); - auto label = new QLabel(parameter->name() + ":"); + auto label = new QLabel(parameter->name() + QLatin1Char(':')); if (dialog_layout->itemAt(row, QFormLayout::FieldRole)) { dialog_layout->insertRow(row, label, field); diff --git a/src/gui/widgets/editor_settings_page.cpp b/src/gui/widgets/editor_settings_page.cpp new file mode 100644 index 000000000..f499a5a86 --- /dev/null +++ b/src/gui/widgets/editor_settings_page.cpp @@ -0,0 +1,147 @@ +/* + * Copyright 2012, 2013 Jan Dalheimer + * Copyright 2012-2016 Kai Pastor + * + * This file is part of OpenOrienteering. + * + * OpenOrienteering 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. + * + * OpenOrienteering 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 OpenOrienteering. If not, see . + */ + +#include "editor_settings_page.h" + +#include +#include +#include + +#include "../modifier_key.h" +#include "../../util_gui.h" + + +EditorSettingsPage::EditorSettingsPage(QWidget* parent) + : SettingsPage(parent) +{ + auto layout = new QFormLayout(this); + + antialiasing = new QCheckBox(tr("High quality map display (antialiasing)"), this); + antialiasing->setToolTip(tr("Antialiasing makes the map look much better, but also slows down the map display")); + layout->addRow(antialiasing); + + text_antialiasing = new QCheckBox(tr("High quality text display in map (antialiasing), slow"), this); + text_antialiasing->setToolTip(tr("Antialiasing makes the map look much better, but also slows down the map display")); + layout->addRow(text_antialiasing); + + tolerance = Util::SpinBox::create(0, 50, tr("mm", "millimeters")); + layout->addRow(tr("Click tolerance:"), tolerance); + + snap_distance = Util::SpinBox::create(0, 100, tr("mm", "millimeters")); + layout->addRow(tr("Snap distance (%1):").arg(ModifierKey::shift()), snap_distance); + + fixed_angle_stepping = Util::SpinBox::create(1, 180, trUtf8("°", "Degree sign for angles")); + layout->addRow(tr("Stepping of fixed angle mode (%1):").arg(ModifierKey::control()), fixed_angle_stepping); + + select_symbol_of_objects = new QCheckBox(tr("When selecting an object, automatically select its symbol, too")); + layout->addRow(select_symbol_of_objects); + + zoom_out_away_from_cursor = new QCheckBox(tr("Zoom away from cursor when zooming out")); + layout->addRow(zoom_out_away_from_cursor); + + draw_last_point_on_right_click = new QCheckBox(tr("Drawing tools: set last point on finishing with right click")); + layout->addRow(draw_last_point_on_right_click); + + keep_settings_of_closed_templates = new QCheckBox(tr("Templates: keep settings of closed templates")); + layout->addRow(keep_settings_of_closed_templates); + + + layout->addItem(Util::SpacerItem::create(this)); + layout->addRow(Util::Headline::create(tr("Edit tool:"))); + + edit_tool_delete_bezier_point_action = new QComboBox(); + edit_tool_delete_bezier_point_action->addItem(tr("Retain old shape"), (int)Settings::DeleteBezierPoint_RetainExistingShape); + edit_tool_delete_bezier_point_action->addItem(tr("Reset outer curve handles"), (int)Settings::DeleteBezierPoint_ResetHandles); + edit_tool_delete_bezier_point_action->addItem(tr("Keep outer curve handles"), (int)Settings::DeleteBezierPoint_KeepHandles); + layout->addRow(tr("Action on deleting a curve point with %1:").arg(ModifierKey::control()), edit_tool_delete_bezier_point_action); + + edit_tool_delete_bezier_point_action_alternative = new QComboBox(); + edit_tool_delete_bezier_point_action_alternative->addItem(tr("Retain old shape"), (int)Settings::DeleteBezierPoint_RetainExistingShape); + edit_tool_delete_bezier_point_action_alternative->addItem(tr("Reset outer curve handles"), (int)Settings::DeleteBezierPoint_ResetHandles); + edit_tool_delete_bezier_point_action_alternative->addItem(tr("Keep outer curve handles"), (int)Settings::DeleteBezierPoint_KeepHandles); + layout->addRow(tr("Action on deleting a curve point with %1:").arg(ModifierKey::controlShift()), edit_tool_delete_bezier_point_action_alternative); + + layout->addItem(Util::SpacerItem::create(this)); + layout->addRow(Util::Headline::create(tr("Rectangle tool:"))); + + rectangle_helper_cross_radius = Util::SpinBox::create(0, 999999, tr("mm", "millimeters")); + layout->addRow(tr("Radius of helper cross:"), rectangle_helper_cross_radius); + + rectangle_preview_line_width = new QCheckBox(tr("Preview the width of lines with helper cross")); + layout->addRow(rectangle_preview_line_width); + + + connect(antialiasing, &QAbstractButton::toggled, text_antialiasing, &QCheckBox::setEnabled); + + updateWidgets(); +} + +EditorSettingsPage::~EditorSettingsPage() +{ + // nothing, not inlined +} + +QString EditorSettingsPage::title() const +{ + return tr("Editor"); +} + +void EditorSettingsPage::apply() +{ + setSetting(Settings::MapDisplay_Antialiasing, antialiasing->isChecked()); + setSetting(Settings::MapDisplay_TextAntialiasing, text_antialiasing->isChecked()); + setSetting(Settings::MapEditor_ClickToleranceMM, tolerance->value()); + setSetting(Settings::MapEditor_SnapDistanceMM, snap_distance->value()); + setSetting(Settings::MapEditor_FixedAngleStepping, fixed_angle_stepping->value()); + setSetting(Settings::MapEditor_ChangeSymbolWhenSelecting, select_symbol_of_objects->isChecked()); + setSetting(Settings::MapEditor_ZoomOutAwayFromCursor, zoom_out_away_from_cursor->isChecked()); + setSetting(Settings::MapEditor_DrawLastPointOnRightClick, draw_last_point_on_right_click->isChecked()); + setSetting(Settings::Templates_KeepSettingsOfClosed, keep_settings_of_closed_templates->isChecked()); + setSetting(Settings::EditTool_DeleteBezierPointAction, edit_tool_delete_bezier_point_action->currentData()); + setSetting(Settings::EditTool_DeleteBezierPointActionAlternative, edit_tool_delete_bezier_point_action_alternative->currentData()); + setSetting(Settings::RectangleTool_HelperCrossRadiusMM, rectangle_helper_cross_radius->value()); + setSetting(Settings::RectangleTool_PreviewLineWidth, rectangle_preview_line_width->isChecked()); +} + +void EditorSettingsPage::reset() +{ + updateWidgets(); +} + +void EditorSettingsPage::updateWidgets() +{ + antialiasing->setChecked(getSetting(Settings::MapDisplay_Antialiasing).toBool()); + text_antialiasing->setEnabled(antialiasing->isChecked()); + text_antialiasing->setChecked(getSetting(Settings::MapDisplay_TextAntialiasing).toBool()); + tolerance->setValue(getSetting(Settings::MapEditor_ClickToleranceMM).toInt()); + snap_distance->setValue(getSetting(Settings::MapEditor_SnapDistanceMM).toInt()); + fixed_angle_stepping->setValue(getSetting(Settings::MapEditor_FixedAngleStepping).toInt()); + select_symbol_of_objects->setChecked(getSetting(Settings::MapEditor_ChangeSymbolWhenSelecting).toBool()); + zoom_out_away_from_cursor->setChecked(getSetting(Settings::MapEditor_ZoomOutAwayFromCursor).toBool()); + draw_last_point_on_right_click->setChecked(getSetting(Settings::MapEditor_DrawLastPointOnRightClick).toBool()); + keep_settings_of_closed_templates->setChecked(getSetting(Settings::Templates_KeepSettingsOfClosed).toBool()); + + edit_tool_delete_bezier_point_action->setCurrentIndex(edit_tool_delete_bezier_point_action->findData(getSetting(Settings::EditTool_DeleteBezierPointAction).toInt())); + edit_tool_delete_bezier_point_action_alternative->setCurrentIndex(edit_tool_delete_bezier_point_action_alternative->findData(getSetting(Settings::EditTool_DeleteBezierPointActionAlternative).toInt())); + + rectangle_helper_cross_radius->setValue(getSetting(Settings::RectangleTool_HelperCrossRadiusMM).toInt()); + rectangle_preview_line_width->setChecked(getSetting(Settings::RectangleTool_PreviewLineWidth).toBool()); +} + diff --git a/src/gui/widgets/editor_settings_page.h b/src/gui/widgets/editor_settings_page.h new file mode 100644 index 000000000..f1279e658 --- /dev/null +++ b/src/gui/widgets/editor_settings_page.h @@ -0,0 +1,69 @@ +/* + * Copyright 2012, 2013 Jan Dalheimer + * Copyright 2013-2016 Kai Pastor + * + * This file is part of OpenOrienteering. + * + * OpenOrienteering 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. + * + * OpenOrienteering 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 OpenOrienteering. If not, see . + */ + +#ifndef OPENORIENTEERING_EDITOR_SETTINGS_PAGE_H +#define OPENORIENTEERING_EDITOR_SETTINGS_PAGE_H + +#include "settings_page.h" + +class QCheckBox; +class QComboBox; +class QSpinBox; + +class MainWindow; + + +class EditorSettingsPage : public SettingsPage +{ +Q_OBJECT +public: + explicit EditorSettingsPage(QWidget* parent = nullptr); + + ~EditorSettingsPage() override; + + QString title() const override; + + void apply() override; + + void reset() override; + +protected: + void updateWidgets(); + +private: + QCheckBox* antialiasing; + QCheckBox* text_antialiasing; + QSpinBox* tolerance; + QSpinBox* snap_distance; + QSpinBox* fixed_angle_stepping; + QCheckBox* select_symbol_of_objects; + QCheckBox* zoom_out_away_from_cursor; + QCheckBox* draw_last_point_on_right_click; + QCheckBox* keep_settings_of_closed_templates; + + QComboBox* edit_tool_delete_bezier_point_action; + QComboBox* edit_tool_delete_bezier_point_action_alternative; + + QSpinBox* rectangle_helper_cross_radius; + QCheckBox* rectangle_preview_line_width; +}; + + +#endif diff --git a/src/gui/widgets/general_settings_page.cpp b/src/gui/widgets/general_settings_page.cpp new file mode 100644 index 000000000..6fab99fd8 --- /dev/null +++ b/src/gui/widgets/general_settings_page.cpp @@ -0,0 +1,369 @@ +/* + * Copyright 2012, 2013 Jan Dalheimer + * Copyright 2012-2016 Kai Pastor + * + * This file is part of OpenOrienteering. + * + * OpenOrienteering 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. + * + * OpenOrienteering 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 OpenOrienteering. If not, see . + */ + +#include "general_settings_page.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "home_screen_widget.h" +#include "../main_window.h" +#include "../../util_gui.h" +#include "../../util_translation.h" +#include "../../util/scoped_signals_blocker.h" + + +GeneralSettingsPage::GeneralSettingsPage(QWidget* parent) +: SettingsPage(parent) +, translation_file(getSetting(Settings::General_TranslationFile).toString()) +{ + auto layout = new QFormLayout(this); + + layout->addRow(Util::Headline::create(tr("Appearance"))); + + auto language_widget = new QWidget(); + auto language_layout = new QHBoxLayout(language_widget); + language_layout->setContentsMargins({}); + layout->addRow(tr("Language:"), language_widget); + + language_box = new QComboBox(this); + language_layout->addWidget(language_box); + + QAbstractButton* language_file_button = new QToolButton(); + if (MainWindow::mobileMode()) + { + language_file_button->setVisible(false); + } + else + { + language_file_button->setIcon(QIcon(QLatin1String(":/images/open.png"))); + } + language_layout->addWidget(language_file_button); + + layout->addItem(Util::SpacerItem::create(this)); + layout->addRow(Util::Headline::create(tr("Screen"))); + + auto ppi_widget = new QWidget(); + auto ppi_layout = new QHBoxLayout(ppi_widget); + ppi_layout->setContentsMargins({}); + layout->addRow(tr("Pixels per inch:"), ppi_widget); + + ppi_edit = Util::SpinBox::create(2, 0.01, 9999); + ppi_layout->addWidget(ppi_edit); + + QAbstractButton* ppi_calculate_button = new QToolButton(); + ppi_calculate_button->setIcon(QIcon(QLatin1String(":/images/settings.png"))); + ppi_layout->addWidget(ppi_calculate_button); + + layout->addItem(Util::SpacerItem::create(this)); + layout->addRow(Util::Headline::create(tr("Program start"))); + + open_mru_check = new QCheckBox(AbstractHomeScreenWidget::tr("Open most recently used file")); + layout->addRow(open_mru_check); + + tips_visible_check = new QCheckBox(AbstractHomeScreenWidget::tr("Show tip of the day")); + layout->addRow(tips_visible_check); + + layout->addItem(Util::SpacerItem::create(this)); + layout->addRow(Util::Headline::create(tr("Saving files"))); + + compatibility_check = new QCheckBox(tr("Retain compatibility with Mapper %1").arg(QLatin1String("0.5"))); + layout->addRow(compatibility_check); + + // Possible point: limit size of undo/redo journal + + autosave_check = new QCheckBox(tr("Save information for automatic recovery")); + layout->addRow(autosave_check); + + autosave_interval_edit = Util::SpinBox::create(1, 120, tr("min", "unit minutes"), 1); + layout->addRow(tr("Recovery information saving interval:"), autosave_interval_edit); + + layout->addItem(Util::SpacerItem::create(this)); + layout->addRow(Util::Headline::create(tr("File import and export"))); + + encoding_box = new QComboBox(); + encoding_box->addItem(QLatin1String("System")); + encoding_box->addItem(QLatin1String("Windows-1250")); + encoding_box->addItem(QLatin1String("Windows-1252")); + encoding_box->addItem(QLatin1String("ISO-8859-1")); + encoding_box->addItem(QLatin1String("ISO-8859-15")); + encoding_box->setEditable(true); + QStringList availableCodecs; + for (const QByteArray& item : QTextCodec::availableCodecs()) + { + availableCodecs.append(QString::fromUtf8(item)); + } + if (!availableCodecs.empty()) + { + availableCodecs.sort(Qt::CaseInsensitive); + availableCodecs.removeDuplicates(); + encoding_box->addItem(tr("More...")); + } + QCompleter* completer = new QCompleter(availableCodecs, this); + completer->setCaseSensitivity(Qt::CaseInsensitive); + encoding_box->setCompleter(completer); + layout->addRow(tr("8-bit encoding:"), encoding_box); + + ocd_importer_check = new QCheckBox(tr("Use the new OCD importer also for version 8 files").replace(QLatin1Char('8'), QString::fromLatin1("6-8"))); + layout->addRow(ocd_importer_check); + + updateWidgets(); + + connect(language_file_button, &QAbstractButton::clicked, this, &GeneralSettingsPage::openTranslationFileDialog); + connect(ppi_calculate_button, &QAbstractButton::clicked, this, &GeneralSettingsPage::openPPICalculationDialog); + connect(encoding_box, &QComboBox::currentTextChanged, this, &GeneralSettingsPage::encodingChanged); + connect(autosave_check, &QAbstractButton::toggled, autosave_interval_edit, &QWidget::setEnabled); + connect(autosave_check, &QAbstractButton::toggled, layout->labelForField(autosave_interval_edit), &QWidget::setEnabled); + +} + +GeneralSettingsPage::~GeneralSettingsPage() +{ + // nothing, not inlined +} + +QString GeneralSettingsPage::title() const +{ + return tr("General"); +} + +void GeneralSettingsPage::apply() +{ + auto language = language_box->currentData(); + if (language != getSetting(Settings::General_Language) + || translation_file != getSetting(Settings::General_TranslationFile).toString()) + { + // Show an message box in the new language. + TranslationUtil translation((QLocale::Language)language.toInt(), translation_file); + auto new_language = translation.getLocale().language(); + switch (new_language) + { + case QLocale::AnyLanguage: + case QLocale::C: + case QLocale::English: + QMessageBox::information(window(), QLatin1String("Notice"), QLatin1String("The program must be restarted for the language change to take effect!")); + break; + + default: + qApp->installEventFilter(this); + qApp->installTranslator(&translation.getQtTranslator()); + qApp->installTranslator(&translation.getAppTranslator()); + QMessageBox::information(window(), tr("Notice"), tr("The program must be restarted for the language change to take effect!")); + qApp->removeTranslator(&translation.getAppTranslator()); + qApp->removeTranslator(&translation.getQtTranslator()); + qApp->removeEventFilter(this); + } + + setSetting(Settings::General_Language, new_language); + setSetting(Settings::General_TranslationFile, translation_file); +#if defined(Q_OS_MAC) + // The native [file] dialogs will use the first element of the + // AppleLanguages array in the application's .plist file - + // and this file is also the one used by QSettings. + const QString mapper_language(translation.getLocale().name().left(2)); + QSettings().setValue(QString::fromLatin1("AppleLanguages"), { mapper_language }); +#endif + } + + setSetting(Settings::General_OpenMRUFile, open_mru_check->isChecked()); + setSetting(Settings::HomeScreen_TipsVisible, tips_visible_check->isChecked()); + setSetting(Settings::General_NewOcd8Implementation, ocd_importer_check->isChecked()); + setSetting(Settings::General_RetainCompatiblity, compatibility_check->isChecked()); + setSetting(Settings::General_PixelsPerInch, ppi_edit->value()); + + auto name_latin1 = encoding_box->currentText().toLatin1(); + if (name_latin1 == "System" + || QTextCodec::codecForName(name_latin1)) + { + setSetting(Settings::General_Local8BitEncoding, name_latin1); + } + + int interval = autosave_interval_edit->value(); + if (!autosave_check->isChecked()) + interval = -interval; + setSetting(Settings::General_AutosaveInterval, interval); +} + +void GeneralSettingsPage::reset() +{ + translation_file = getSetting(Settings::General_TranslationFile).toString(); + updateWidgets(); +} + +void GeneralSettingsPage::updateLanguageBox(QVariant language) +{ + LanguageCollection language_map = TranslationUtil::getAvailableLanguages(); + + // If there is an explicit translation file, use its locale + QString locale_name = TranslationUtil::localeNameForFile(translation_file); + if (!locale_name.isEmpty()) + { + QLocale file_locale(locale_name); + QString language_name = file_locale.nativeLanguageName(); + if (!language_map.contains(language_name)) + language_map.insert(language_name, file_locale.language()); + } + + // Update the language box + const QSignalBlocker block(language_box); + language_box->clear(); + + for (auto it = language_map.constBegin(),end = language_map.constEnd(); it != end; ++it) + language_box->addItem(it.key(), (int)it.value()); + + // Select current language + int index = language_box->findData(language); + if (index < 0) + { + language = QLocale::English; + index = language_box->findData(language); + } + language_box->setCurrentIndex(index); +} + +void GeneralSettingsPage::updateWidgets() +{ + updateLanguageBox(getSetting(Settings::General_Language)); + + ppi_edit->setValue(getSetting(Settings::General_PixelsPerInch).toFloat()); + open_mru_check->setChecked(getSetting(Settings::General_OpenMRUFile).toBool()); + tips_visible_check->setChecked(getSetting(Settings::HomeScreen_TipsVisible).toBool()); + compatibility_check->setChecked(getSetting(Settings::General_RetainCompatiblity).toBool()); + + int autosave_interval = getSetting(Settings::General_AutosaveInterval).toInt(); + autosave_check->setChecked(autosave_interval > 0); + autosave_interval_edit->setEnabled(autosave_interval > 0); + autosave_interval_edit->setValue(qAbs(autosave_interval)); + + encoding_box->setCurrentText(getSetting(Settings::General_Local8BitEncoding).toString()); + ocd_importer_check->setChecked(getSetting(Settings::General_NewOcd8Implementation).toBool()); +} + +// slot +void GeneralSettingsPage::encodingChanged(const QString& name) +{ + const QSignalBlocker block(encoding_box); + + if (name == tr("More...")) + { + encoding_box->setCurrentText(QString()); + encoding_box->completer()->setCompletionPrefix(QString()); + encoding_box->completer()->complete(); + return; + } + + auto name_latin1 = name.toLatin1(); + QTextCodec* codec = (name_latin1 == "System") + ? QTextCodec::codecForLocale() + : QTextCodec::codecForName(name_latin1); + if (codec) + { + encoding_box->setCurrentText(name); + } +} + +// slot +void GeneralSettingsPage::openTranslationFileDialog() +{ + QString filename = translation_file; + if (filename.isEmpty()) + filename = getSetting(Settings::General_TranslationFile).toString(); + + filename = QFileDialog::getOpenFileName(this, + tr("Open translation"), filename, tr("Translation files (*.qm)")); + if (!filename.isNull()) + { + QString locale_name(TranslationUtil::localeNameForFile(filename)); + if (locale_name.isEmpty()) + { + QMessageBox::critical(this, tr("Open translation"), + tr("The selected file is not a valid translation.") ); + } + else + { + translation_file = filename; + updateLanguageBox(QLocale(locale_name).language()); + } + } +} + +// slot +void GeneralSettingsPage::openPPICalculationDialog() +{ + int primary_screen_width = QApplication::primaryScreen()->size().width(); + int primary_screen_height = QApplication::primaryScreen()->size().height(); + float screen_diagonal_pixels = qSqrt(primary_screen_width*primary_screen_width + primary_screen_height*primary_screen_height); + + float old_ppi = ppi_edit->value(); + float old_screen_diagonal_inches = screen_diagonal_pixels / old_ppi; + + QDialog* dialog = new QDialog(window(), Qt::WindowSystemMenuHint | Qt::WindowTitleHint); + if (MainWindow::mobileMode()) + { + dialog->setGeometry(window()->geometry()); + } + + auto layout = new QVBoxLayout(dialog); + + auto form_layout = new QFormLayout(); + + QLabel* resolution_display = new QLabel(tr("%1 x %2").arg(primary_screen_width).arg(primary_screen_height)); + form_layout->addRow(tr("Primary screen resolution in pixels:"), resolution_display); + + QDoubleSpinBox* size_edit = Util::SpinBox::create(2, 0.01, 9999); + size_edit->setValue(old_screen_diagonal_inches); + form_layout->addRow(tr("Primary screen size in inches (diagonal):"), size_edit); + + layout->addLayout(form_layout); + + layout->addItem(Util::SpacerItem::create(this)); + + QDialogButtonBox* button_box = new QDialogButtonBox(QDialogButtonBox::Cancel | QDialogButtonBox::Ok); + layout->addWidget(button_box); + + connect(button_box, &QDialogButtonBox::accepted, dialog, &QDialog::accept); + connect(button_box, &QDialogButtonBox::rejected, dialog, &QDialog::reject); + dialog->exec(); + + if (dialog->result() == QDialog::Accepted) + { + ppi_edit->setValue(screen_diagonal_pixels / size_edit->value()); + } +} + +bool GeneralSettingsPage::eventFilter(QObject* /* watched */, QEvent* event) +{ + if (event->type() == QEvent::LanguageChange) + return true; + + return false; +} + diff --git a/src/gui/widgets/general_settings_page.h b/src/gui/widgets/general_settings_page.h new file mode 100644 index 000000000..4d12b331d --- /dev/null +++ b/src/gui/widgets/general_settings_page.h @@ -0,0 +1,84 @@ +/* + * Copyright 2012, 2013 Jan Dalheimer + * Copyright 2013-2016 Kai Pastor + * + * This file is part of OpenOrienteering. + * + * OpenOrienteering 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. + * + * OpenOrienteering 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 OpenOrienteering. If not, see . + */ + +#ifndef OPENORIENTEERING_GENERAL_SETTINGS_PAGE_H +#define OPENORIENTEERING_GENERAL_SETTINGS_PAGE_H + +#include "settings_page.h" + +class QCheckBox; +class QComboBox; +class QDoubleSpinBox; +class QSpinBox; + + +class GeneralSettingsPage : public SettingsPage +{ +Q_OBJECT +public: + explicit GeneralSettingsPage(QWidget* parent = nullptr); + + ~GeneralSettingsPage() override; + + QString title() const override; + + void apply() override; + + void reset() override; + +protected: + /** + * Adds the available languages to the language combo box, + * and sets the current element. + */ + void updateLanguageBox(QVariant language); + + void updateWidgets(); + + /** + * This event filter stops LanguageChange events. + */ + bool eventFilter(QObject* watched, QEvent* event) override; + +private slots: + void openTranslationFileDialog(); + + void openPPICalculationDialog(); + + void encodingChanged(const QString& name); + +private: + QString translation_file; + + QComboBox* language_box; + + QDoubleSpinBox* ppi_edit; + QCheckBox* open_mru_check; + QCheckBox* tips_visible_check; + + QCheckBox* compatibility_check; + QCheckBox* autosave_check; + QSpinBox* autosave_interval_edit; + + QComboBox* encoding_box; + QCheckBox* ocd_importer_check; +}; + +#endif diff --git a/src/gui/widgets/home_screen_widget.cpp b/src/gui/widgets/home_screen_widget.cpp index 2a8535649..17507c8c3 100644 --- a/src/gui/widgets/home_screen_widget.cpp +++ b/src/gui/widgets/home_screen_widget.cpp @@ -25,18 +25,22 @@ #include #include #include +#include #include #include +#include #include #include #include #include #include +#include #include #include #include "../home_screen_controller.h" #include "../main_window.h" +#include "../settings_dialog.h" #include "../../file_format_registry.h" #include "../../mapper_resource.h" @@ -107,7 +111,7 @@ QAbstractButton* AbstractHomeScreenWidget::makeButton(const QString& text, const HomeScreenWidgetDesktop::HomeScreenWidgetDesktop(HomeScreenController* controller, QWidget* parent) : AbstractHomeScreenWidget(controller, parent) { - QLabel* title_label = new QLabel(QString("")); + QLabel* title_label = new QLabel(QString::fromLatin1("")); title_label->setAlignment(Qt::AlignCenter); QWidget* menu_widget = makeMenuWidget(controller, parent); QWidget* recent_files_widget = makeRecentFilesWidget(controller, parent); @@ -140,25 +144,25 @@ QWidget* HomeScreenWidgetDesktop::makeMenuWidget(HomeScreenController* controlle QLabel* menu_headline = makeHeadline(tr("Activities")); menu_layout->addWidget(menu_headline); QAbstractButton* button_new_map = makeButton( - tr("Create a new map ..."), QIcon(":/images/new.png")); + tr("Create a new map ..."), QIcon(QString::fromLatin1(":/images/new.png"))); menu_layout->addWidget(button_new_map); QAbstractButton* button_open_map = makeButton( - tr("Open map ..."), QIcon(":/images/open.png")); + tr("Open map ..."), QIcon(QString::fromLatin1(":/images/open.png"))); menu_layout->addWidget(button_open_map); menu_layout->addStretch(1); QAbstractButton* button_settings = makeButton( - tr("Settings"), QIcon(":/images/settings.png")); + tr("Settings"), QIcon(QString::fromLatin1(":/images/settings.png"))); menu_layout->addWidget(button_settings); QAbstractButton* button_about = makeButton( - tr("About %1", "As in 'About OpenOrienteering Mapper'").arg(window->appName()), QIcon(":/images/about.png")); + tr("About %1", "As in 'About OpenOrienteering Mapper'").arg(window->appName()), QIcon(QString::fromLatin1(":/images/about.png"))); menu_layout->addWidget(button_about); QAbstractButton* button_help = makeButton( - tr("Help"), QIcon(":/images/help.png")); + tr("Help"), QIcon(QString::fromLatin1(":/images/help.png"))); menu_layout->addWidget(button_help); QAbstractButton* button_exit = makeButton( - tr("Exit"), QIcon(":/qt-project.org/styles/commonstyle/images/standardbutton-close-32.png")); // From Qt5 + tr("Exit"), QIcon(QString::fromLatin1(":/qt-project.org/styles/commonstyle/images/standardbutton-close-32.png"))); // From Qt5 menu_layout->addWidget(button_exit); connect(button_new_map, SIGNAL(clicked(bool)), window, SLOT(showNewMapWizard())); @@ -196,11 +200,11 @@ QWidget* HomeScreenWidgetDesktop::makeRecentFilesWidget(HomeScreenController* co recent_files_list->setFont(list_font); recent_files_list->setSpacing(pixel_size/2); recent_files_list->setCursor(Qt::PointingHandCursor); - recent_files_list->setStyleSheet(" \ + recent_files_list->setStyleSheet(QString::fromLatin1(" \ QListWidget::item:hover { \ color: palette(highlighted-text); \ background: palette(highlight); \ - } "); + } ")); recent_files_layout->addWidget(recent_files_list, 1, 0, 1, 2); open_mru_file_check = new QCheckBox(tr("Open most recently used file on start")); @@ -234,9 +238,9 @@ QWidget* HomeScreenWidgetDesktop::makeTipsWidget(HomeScreenController* controlle tips_check->setChecked(true); tips_layout->addWidget(tips_check, 2, 0, 1, 1); tips_layout->addWidget(tips_label, 1, 0, 1, 3); - QPushButton* prev_button = new QPushButton(QIcon(":/images/arrow-left.png"), tr("Previous")); + QPushButton* prev_button = new QPushButton(QIcon(QString::fromLatin1(":/images/arrow-left.png")), tr("Previous")); tips_layout->addWidget(prev_button, 2, 1, 1, 1); - QPushButton* next_button = new QPushButton(QIcon(":/images/arrow-right.png"), tr("Next")); + QPushButton* next_button = new QPushButton(QIcon(QString::fromLatin1(":/images/arrow-right.png")), tr("Next")); tips_layout->addWidget(next_button, 2, 2, 1, 1); tips_layout->setRowStretch(1, 1); @@ -317,7 +321,7 @@ void HomeScreenWidgetDesktop::setTipsVisible(bool state) HomeScreenWidgetMobile::HomeScreenWidgetMobile(HomeScreenController* controller, QWidget* parent) : AbstractHomeScreenWidget(controller, parent) { - title_pixmap = QPixmap::fromImage(QImage(":/images/title.png")); + title_pixmap = QPixmap::fromImage(QImage(QString::fromLatin1(":/images/title.png"))); title_label = new QLabel(); title_label->setPixmap(title_pixmap); @@ -327,6 +331,8 @@ HomeScreenWidgetMobile::HomeScreenWidgetMobile(HomeScreenController* controller, examples_button = new QPushButton(tr("Examples")); connect(examples_button, &QPushButton::clicked, this, &HomeScreenWidgetMobile::showExamples); + auto settings_button = new QPushButton(HomeScreenWidgetDesktop::tr("Settings")); + connect(settings_button, &QPushButton::clicked, controller->getWindow(), &MainWindow::showSettings); QPushButton* help_button = new QPushButton(HomeScreenWidgetDesktop::tr("Help")); connect(help_button, &QPushButton::clicked, controller->getWindow(), &MainWindow::showHelp); QPushButton* about_button = new QPushButton(tr("About Mapper")); @@ -335,6 +341,7 @@ HomeScreenWidgetMobile::HomeScreenWidgetMobile(HomeScreenController* controller, buttons_layout->setContentsMargins(0, 0, 0, 0); buttons_layout->addWidget(examples_button); buttons_layout->addStretch(1); + buttons_layout->addWidget(settings_button); buttons_layout->addWidget(help_button); buttons_layout->addWidget(about_button); @@ -420,6 +427,15 @@ void HomeScreenWidgetMobile::showExamples() } } +void HomeScreenWidgetMobile::showSettings() +{ + auto window = this->window(); + + SettingsDialog dialog(window); + dialog.setGeometry(window->geometry()); + dialog.exec(); +} + void HomeScreenWidgetMobile::fileClicked(QListWidgetItem* item) { QString path = item->data(Qt::UserRole).toString(); @@ -456,37 +472,42 @@ QWidget* HomeScreenWidgetMobile::makeFileListWidget(HomeScreenController* contro file_list->setFont(list_font); file_list->setSpacing(pixel_size/2); file_list->setCursor(Qt::PointingHandCursor); - file_list->setStyleSheet(" \ + file_list->setStyleSheet(QString::fromLatin1(" \ QListWidget::item:hover { \ color: palette(highlighted-text); \ background: palette(highlight); \ - } "); + } ")); file_list_stack->addWidget(file_list); // Look for map files at device-specific locations #ifdef Q_OS_ANDROID QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); // Actual SD card mount points may be found in secondary storage - QStringList folder_list = env.value("SECONDARY_STORAGE").split(':'); + QStringList folder_list = env.value(QString::fromLatin1("SECONDARY_STORAGE")).split(QLatin1Char{':'}); // The primary volume that can be accessed externally (from PC) - QString external_storage = env.value("EXTERNAL_STORAGE"); + QString external_storage = env.value(QString::fromLatin1("EXTERNAL_STORAGE")); if (!external_storage.isEmpty()) folder_list.insert(0, external_storage); // Optional fallback locations - folder_list << "/" << "/mnt" << "/mnt/sdcard" << "/sdcard" << "/storage"; + folder_list << QString::fromLatin1("/") + << QString::fromLatin1("/mnt") + << QString::fromLatin1("/mnt/sdcard") + << QString::fromLatin1("/sdcard") + << QString::fromLatin1("/storage"); bool oomapper_found = false; for (auto&& path : folder_list) { - if (oomapper_found && path == "/") + if (oomapper_found && path == QLatin1String{"/"}) // Don't need fallback (avoid duplicate entries) break; QDir dir(path); - if (dir.exists("OOMapper")) + auto oomapper = QString::fromLatin1("OOMapper"); + if (dir.exists(oomapper)) { oomapper_found = true; - addFilesToFileList(file_list, dir.filePath("OOMapper")); + addFilesToFileList(file_list, dir.filePath(oomapper)); } } #endif diff --git a/src/gui/widgets/home_screen_widget.h b/src/gui/widgets/home_screen_widget.h index 9a2b27206..99b3be183 100644 --- a/src/gui/widgets/home_screen_widget.h +++ b/src/gui/widgets/home_screen_widget.h @@ -173,6 +173,9 @@ public slots: * if they are not already there. */ void showExamples(); + /** Shows the settings dialog, adjusted for small screens. */ + void showSettings(); + protected slots: /** Opens a file when its is list item is clicked. */ void fileClicked(QListWidgetItem* item); diff --git a/src/gui/widgets/mapper_proxystyle.cpp b/src/gui/widgets/mapper_proxystyle.cpp index 0a40540fc..971db8c24 100644 --- a/src/gui/widgets/mapper_proxystyle.cpp +++ b/src/gui/widgets/mapper_proxystyle.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 Kai Pastor + * Copyright 2013-2016 Kai Pastor * * This file is part of OpenOrienteering. * @@ -20,6 +20,7 @@ #include "mapper_proxystyle.h" +#include #include #include #include @@ -159,3 +160,18 @@ int MapperProxyStyle::pixelMetric(PixelMetric metric, const QStyleOption* option return QProxyStyle::pixelMetric(metric, option, widget); } + +int MapperProxyStyle::styleHint(QStyle::StyleHint hint, const QStyleOption* option, const QWidget* widget, QStyleHintReturn* return_data) const +{ + switch (hint) + { +#ifdef Q_OS_ANDROID + case QStyle::SH_FormLayoutWrapPolicy: + return QFormLayout::WrapLongRows; +#endif + default: + break; + } + + return QProxyStyle::styleHint(hint, option, widget, return_data); +} diff --git a/src/gui/widgets/mapper_proxystyle.h b/src/gui/widgets/mapper_proxystyle.h index 9e48b9d1d..67c57a511 100644 --- a/src/gui/widgets/mapper_proxystyle.h +++ b/src/gui/widgets/mapper_proxystyle.h @@ -1,5 +1,5 @@ /* - * Copyright 2013, 2015 Kai Pastor + * Copyright 2013, 2016 Kai Pastor * * This file is part of OpenOrienteering. * @@ -68,6 +68,14 @@ Q_OBJECT */ int pixelMetric(PixelMetric metric, const QStyleOption* option = nullptr, const QWidget* widget = nullptr) const override; + /** + * Returns adjusted style hints. + * + * On Android: + * - QStyle::SH_FormLayoutWrapPolicy is QFormLayout::QFormLayout::WrapLongRows. + */ + int styleHint(StyleHint hint, const QStyleOption* option = nullptr, const QWidget* widget = nullptr, QStyleHintReturn* return_data = nullptr) const override; + private: void drawSegmentedButton(int segment, PrimitiveElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const; diff --git a/src/gui/widgets/measure_widget.cpp b/src/gui/widgets/measure_widget.cpp index 60a636e04..5a8a19688 100644 --- a/src/gui/widgets/measure_widget.cpp +++ b/src/gui/widgets/measure_widget.cpp @@ -23,7 +23,6 @@ #include #include -#include #include "../../map.h" #include "../../object.h" @@ -69,7 +68,7 @@ void MeasureWidget::objectSelectionChanged() { const Object* object = *begin(selected_objects); const Symbol* symbol = object->getSymbol(); - headline = symbol->getNumberAsString() % QLatin1Char(' ') % symbol->getName(); + headline = symbol->getNumberAsString() + QLatin1Char(' ') + symbol->getName(); if (object->getType() != Object::Path) { @@ -126,9 +125,9 @@ void MeasureWidget::objectSelectionChanged() if (paper_area < minimum_area && paper_area_text != minimum_area_text) { - extra_text = QLatin1String("") % tr("This object is too small.") % QLatin1String("
") - % tr("The minimimum area is %1 %2.").arg(minimum_area_text, trUtf8("mm²")) - % QLatin1String("
"); + extra_text = QLatin1String("") + tr("This object is too small.") + QLatin1String("
") + + tr("The minimimum area is %1 %2.").arg(minimum_area_text, trUtf8("mm²")) + + QLatin1String("
"); } extra_text.append(tr("Note: Boundary length and area are correct only if there are no self-intersections and holes are used as such.")); } @@ -148,8 +147,8 @@ void MeasureWidget::objectSelectionChanged() if (paper_length < minimum_length && paper_length_text != minimum_length_text) { - extra_text = QLatin1String("") % tr("This line is too short.") % QLatin1String("
") - % tr("The minimum length is %1 %2.").arg(minimum_length_text).arg(tr("mm")); + extra_text = QLatin1String("") + tr("This line is too short.") + QLatin1String("
") + + tr("The minimum length is %1 %2.").arg(minimum_length_text).arg(tr("mm")); } } @@ -158,6 +157,6 @@ void MeasureWidget::objectSelectionChanged() } if (!extra_text.isEmpty()) - body.append(QLatin1String("

") % extra_text % QLatin1String("

")); - setHtml(QLatin1String("

") % headline % QLatin1String("

") % body); + body.append(QLatin1String("

") + extra_text + QLatin1String("

")); + setHtml(QLatin1String("

") + headline + QLatin1String("

") + body); } diff --git a/src/gui/widgets/pie_menu.cpp b/src/gui/widgets/pie_menu.cpp index c322ad61e..6d2cd9a31 100644 --- a/src/gui/widgets/pie_menu.cpp +++ b/src/gui/widgets/pie_menu.cpp @@ -29,6 +29,8 @@ #include #include +#include "../settings.h" + PieMenu::PieMenu(QWidget* parent) : QWidget(parent, Qt::Popup | Qt::FramelessWindowHint), // NOTE: use Qt::Window for debugging to avoid mouse grab minimum_action_count(3), @@ -43,6 +45,12 @@ PieMenu::PieMenu(QWidget* parent) setAutoFillBackground(false); setMouseTracking(true); + auto scale = Settings::getInstance().getSetting(Settings::General_PixelsPerInch).toReal() / 96.0; + if (scale > 1.5) + { + icon_size = qRound(icon_size * scale); + } + updateCachedState(); } diff --git a/src/gui/widgets/settings_page.cpp b/src/gui/widgets/settings_page.cpp new file mode 100644 index 000000000..ee9468f55 --- /dev/null +++ b/src/gui/widgets/settings_page.cpp @@ -0,0 +1,33 @@ +/* + * Copyright 2012 Jan Dalheimer + * Copyright 2012-2016 Kai Pastor + * + * This file is part of OpenOrienteering. + * + * OpenOrienteering 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. + * + * OpenOrienteering 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 OpenOrienteering. If not, see . + */ + +#include "settings_page.h" + + +SettingsPage::SettingsPage(QWidget* parent) +: QWidget(parent) +{ + // nothing +} + +SettingsPage::~SettingsPage() +{ + // nothing, not inlined +} diff --git a/src/gui/widgets/settings_page.h b/src/gui/widgets/settings_page.h new file mode 100644 index 000000000..a46f28930 --- /dev/null +++ b/src/gui/widgets/settings_page.h @@ -0,0 +1,92 @@ +/* + * Copyright 2012 Jan Dalheimer + * Copyright 2013-2016 Kai Pastor + * + * This file is part of OpenOrienteering. + * + * OpenOrienteering 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. + * + * OpenOrienteering 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 OpenOrienteering. If not, see . + */ + +#ifndef OPENORIENTEERING_SETTINGS_PAGE_H +#define OPENORIENTEERING_SETTINGS_PAGE_H + +#include +#include + +#include "../../settings.h" + + +/** + * A widget which serves as a page in the SettingsDialog. + */ +class SettingsPage : public QWidget +{ +Q_OBJECT +public: + /** + * Constructs a new settings page. + */ + explicit SettingsPage(QWidget* parent = nullptr); + + /** + * Destructor. + */ + ~SettingsPage() override; + + /** + * Returns the title of this page. + */ + virtual QString title() const = 0; + +public slots: + /** + * This slot is to transfer the input fields to the settings. + */ + virtual void apply() = 0; + + /** + * This slot is to reset all input widgets to the state of the settings. + */ + virtual void reset() = 0; + +protected: + /** + * Convenience function for retrieving a setting. + */ + static QVariant getSetting(Settings::SettingsEnum setting); + + /** + * Convenience function for changing a setting. + */ + template + static void setSetting(Settings::SettingsEnum setting, T value); + +}; + + + +inline +QVariant SettingsPage::getSetting(Settings::SettingsEnum setting) +{ + return Settings::getInstance().getSetting(setting); +} + +template +void SettingsPage::setSetting(Settings::SettingsEnum setting, T value) +{ + Settings::getInstance().setSetting(setting, QVariant{ value }); +} + + +#endif diff --git a/src/gui/widgets/symbol_dropdown.cpp b/src/gui/widgets/symbol_dropdown.cpp index 681c1fbca..864824eda 100644 --- a/src/gui/widgets/symbol_dropdown.cpp +++ b/src/gui/widgets/symbol_dropdown.cpp @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -59,7 +58,7 @@ SymbolDropDown::SymbolDropDown(const Map* map, int filter, const Symbol* initial continue; } - QString symbol_name = symbol->getNumberAsString() % " " % symbol->getPlainTextName(); + QString symbol_name = symbol->getNumberAsString() + QLatin1Char(' ') + symbol->getPlainTextName(); addItem(QPixmap::fromImage(symbol->getIcon(map)), symbol_name, QVariant::fromValue(symbol)); } setSymbol(initial_symbol); @@ -136,7 +135,7 @@ void SymbolDropDownDelegate::setModelData(QWidget* editor, QAbstractItemModel* m if (symbol) { - model->setData(index, symbol->getNumberAsString() + " " + symbol->getPlainTextName(), Qt::EditRole); + model->setData(index, QVariant(symbol->getNumberAsString() + QLatin1Char(' ') + symbol->getPlainTextName()), Qt::EditRole); model->setData(index, symbol->getIcon(list[0].value()), Qt::DecorationRole); } else diff --git a/src/gui/widgets/symbol_render_widget.cpp b/src/gui/widgets/symbol_render_widget.cpp index 794435496..2e73327a0 100644 --- a/src/gui/widgets/symbol_render_widget.cpp +++ b/src/gui/widgets/symbol_render_widget.cpp @@ -49,6 +49,16 @@ #include "symbol_tooltip.h" +namespace MimeType { + +/// The index of a symbol during drag-and-drop +static const QString oo_symbol_index { QStringLiteral("openorienteering/symbol_index") }; + +/// Symbol definitions +static const QString oo_symbols { QStringLiteral("openorienteering/symbols") }; + +} + //### SymbolIconDecorator ### /** @@ -225,7 +235,7 @@ SymbolRenderWidget::SymbolRenderWidget(Map* map, bool mobile_mode, QWidget* pare context_menu = new QMenu(this); QMenu* new_menu = new QMenu(tr("New symbol"), context_menu); - new_menu->setIcon(QIcon(":/images/plus.png")); + new_menu->setIcon(QIcon(QStringLiteral(":/images/plus.png"))); /*QAction* new_point_action =*/ new_menu->addAction(tr("Point"), this, SLOT(newPointSymbol())); /*QAction* new_line_action =*/ new_menu->addAction(tr("Line"), this, SLOT(newLineSymbol())); /*QAction* new_area_action =*/ new_menu->addAction(tr("Area"), this, SLOT(newAreaSymbol())); @@ -234,23 +244,23 @@ SymbolRenderWidget::SymbolRenderWidget(Map* map, bool mobile_mode, QWidget* pare context_menu->addMenu(new_menu); edit_action = context_menu->addAction(tr("Edit"), this, SLOT(editSymbol())); - duplicate_action = context_menu->addAction(QIcon(":/images/tool-duplicate.png"), tr("Duplicate"), this, SLOT(duplicateSymbol())); - delete_action = context_menu->addAction(QIcon(":/images/minus.png"), tr("Delete"), this, SLOT(deleteSymbols())); - scale_action = context_menu->addAction(QIcon(":/images/tool-scale.png"), tr("Scale..."), this, SLOT(scaleSymbol())); + duplicate_action = context_menu->addAction(QIcon(QStringLiteral(":/images/tool-duplicate.png")), tr("Duplicate"), this, SLOT(duplicateSymbol())); + delete_action = context_menu->addAction(QIcon(QStringLiteral(":/images/minus.png")), tr("Delete"), this, SLOT(deleteSymbols())); + scale_action = context_menu->addAction(QIcon(QStringLiteral(":/images/tool-scale.png")), tr("Scale..."), this, SLOT(scaleSymbol())); context_menu->addSeparator(); - copy_action = context_menu->addAction(QIcon(":/images/copy.png"), tr("Copy"), this, SLOT(copySymbols())); - paste_action = context_menu->addAction(QIcon(":/images/paste.png"), tr("Paste"), this, SLOT(pasteSymbols())); + copy_action = context_menu->addAction(QIcon(QStringLiteral(":/images/copy.png")), tr("Copy"), this, SLOT(copySymbols())); + paste_action = context_menu->addAction(QIcon(QStringLiteral(":/images/paste.png")), tr("Paste"), this, SLOT(pasteSymbols())); context_menu->addSeparator(); - switch_symbol_action = context_menu->addAction(QIcon(":/images/tool-switch-symbol.png"), tr("Switch symbol of selected object(s)"), this, SIGNAL(switchSymbolClicked())); - fill_border_action = context_menu->addAction(QIcon(":/images/tool-fill-border.png"), tr("Fill / Create border for selected object(s)"), this, SIGNAL(fillBorderClicked())); + switch_symbol_action = context_menu->addAction(QIcon(QStringLiteral(":/images/tool-switch-symbol.png")), tr("Switch symbol of selected object(s)"), this, SIGNAL(switchSymbolClicked())); + fill_border_action = context_menu->addAction(QIcon(QStringLiteral(":/images/tool-fill-border.png")), tr("Fill / Create border for selected object(s)"), this, SIGNAL(fillBorderClicked())); // text will be filled in by updateContextMenuState() - select_objects_action = context_menu->addAction(QIcon(":/images/tool-edit.png"), "", this, SLOT(selectObjectsExclusively())); - select_objects_additionally_action = context_menu->addAction(QIcon(":/images/tool-edit.png"), "", this, SLOT(selectObjectsAdditionally())); - deselect_objects_action = context_menu->addAction(QIcon(":/images/tool-edit.png"), "", this, SLOT(deselectObjects())); + select_objects_action = context_menu->addAction(QIcon(QStringLiteral(":/images/tool-edit.png")), {}, this, SLOT(selectObjectsExclusively())); + select_objects_additionally_action = context_menu->addAction(QIcon(QStringLiteral(":/images/tool-edit.png")), {}, this, SLOT(selectObjectsAdditionally())); + deselect_objects_action = context_menu->addAction(QIcon(QStringLiteral(":/images/tool-edit.png")), {}, this, SLOT(deselectObjects())); context_menu->addSeparator(); - hide_action = context_menu->addAction("", this, SLOT(setSelectedSymbolVisibility(bool))); + hide_action = context_menu->addAction({}, this, SLOT(setSelectedSymbolVisibility(bool))); hide_action->setCheckable(true); - protect_action = context_menu->addAction("", this, SLOT(setSelectedSymbolProtection(bool))); + protect_action = context_menu->addAction({}, this, SLOT(setSelectedSymbolProtection(bool))); protect_action->setCheckable(true); context_menu->addSeparator(); @@ -632,7 +642,7 @@ void SymbolRenderWidget::mouseMoveEvent(QMouseEvent* event) QByteArray data; data.append((const char*)¤t_symbol_index, sizeof(int)); - mime_data->setData("openorienteering/symbol_index", data); + mime_data->setData(MimeType::oo_symbol_index, data); drag->setMimeData(mime_data); drag->exec(Qt::MoveAction); @@ -761,13 +771,13 @@ void SymbolRenderWidget::leaveEvent(QEvent* event) void SymbolRenderWidget::dragEnterEvent(QDragEnterEvent* event) { - if (event->mimeData()->hasFormat("openorienteering/symbol_index")) + if (event->mimeData()->hasFormat(MimeType::oo_symbol_index)) event->acceptProposedAction(); } void SymbolRenderWidget::dragMoveEvent(QDragMoveEvent* event) { - if (event->mimeData()->hasFormat("openorienteering/symbol_index")) + if (event->mimeData()->hasFormat(MimeType::oo_symbol_index)) { int row, pos_in_row; if (!dropPosition(event->pos(), row, pos_in_row)) @@ -969,20 +979,20 @@ void SymbolRenderWidget::copySymbols() // Put buffer into clipboard QMimeData* mime_data = new QMimeData(); - mime_data->setData("openorienteering/symbols", buffer.data()); + mime_data->setData(MimeType::oo_symbols, buffer.data()); QApplication::clipboard()->setMimeData(mime_data); } void SymbolRenderWidget::pasteSymbols() { - if (!QApplication::clipboard()->mimeData()->hasFormat("openorienteering/symbols")) + if (!QApplication::clipboard()->mimeData()->hasFormat(MimeType::oo_symbols)) { QMessageBox::warning(NULL, tr("Error"), tr("There are no symbols in clipboard which could be pasted!")); return; } // Get buffer from clipboard - QByteArray byte_array = QApplication::clipboard()->mimeData()->data("openorienteering/symbols"); + QByteArray byte_array = QApplication::clipboard()->mimeData()->data(MimeType::oo_symbols); QBuffer buffer(&byte_array); buffer.open(QIODevice::ReadOnly); @@ -1134,7 +1144,7 @@ void SymbolRenderWidget::updateContextMenuState() edit_action->setEnabled(single_selection); scale_action->setEnabled(have_selection); copy_action->setEnabled(have_selection); - paste_action->setEnabled(QApplication::clipboard()->mimeData()->hasFormat("openorienteering/symbols")); + paste_action->setEnabled(QApplication::clipboard()->mimeData()->hasFormat(MimeType::oo_symbols)); switch_symbol_action->setEnabled(single_symbol_compatible && single_symbol_different); fill_border_action->setEnabled(single_symbol_compatible && single_symbol_different); hide_action->setEnabled(have_selection); diff --git a/src/gui/widgets/symbol_tooltip.cpp b/src/gui/widgets/symbol_tooltip.cpp index 4f4b4271f..7c44dc1b1 100644 --- a/src/gui/widgets/symbol_tooltip.cpp +++ b/src/gui/widgets/symbol_tooltip.cpp @@ -156,7 +156,7 @@ void SymbolToolTip::scheduleShow(const Symbol* symbol, QRect icon_rect) this->icon_rect = icon_rect; this->symbol = symbol; - name_label->setText(symbol->getNumberAsString() + " " + symbol->getName() + ""); + name_label->setText(symbol->getNumberAsString() + QLatin1String(" ") + symbol->getName() + QLatin1String("")); QString help_text(symbol->getDescription()); if (help_text.isEmpty()) @@ -165,8 +165,8 @@ void SymbolToolTip::scheduleShow(const Symbol* symbol, QRect icon_rect) } else { - help_text.replace("\n", "
"); - help_text.remove('\r'); + help_text.replace(QLatin1Char('\n'), QStringLiteral("
")); + help_text.remove(QLatin1Char('\r')); } description_label->setText(help_text); description_label->hide(); diff --git a/src/gui/widgets/tags_widget.cpp b/src/gui/widgets/tags_widget.cpp index 575c38d71..661a7911e 100644 --- a/src/gui/widgets/tags_widget.cpp +++ b/src/gui/widgets/tags_widget.cpp @@ -60,7 +60,7 @@ TagsWidget::TagsWidget(Map* map, MapView* main_view, MapEditorController* contro layout->addWidget(tags_table); - QToolButton* help_button = newToolButton(QIcon(":/images/help.png"), tr("Help")); + QToolButton* help_button = newToolButton(QIcon(QString::fromLatin1(":/images/help.png")), tr("Help")); help_button->setAutoRaise(true); QBoxLayout* all_buttons_layout = new QHBoxLayout(); @@ -71,7 +71,7 @@ TagsWidget::TagsWidget(Map* map, MapView* main_view, MapEditorController* contro style()->pixelMetric(QStyle::PM_LayoutRightMargin, &style_option) / 2, style()->pixelMetric(QStyle::PM_LayoutBottomMargin, &style_option) / 2 ); - all_buttons_layout->addWidget(new QLabel(" "), 1); + all_buttons_layout->addWidget(new QLabel(QString::fromLatin1(" ")), 1); all_buttons_layout->addWidget(help_button); layout->addLayout(all_buttons_layout); @@ -99,7 +99,7 @@ QToolButton* TagsWidget::newToolButton(const QIcon& icon, const QString& text) button->setToolTip(text); button->setIcon(icon); button->setText(text); - button->setWhatsThis("See more"); + button->setWhatsThis(Util::makeWhatThis("templates.html#setup")); return button; } @@ -220,7 +220,7 @@ void TagsWidget::cellChange(int row, int column) else { // Reset current row - tags_table->item(row, 1)->setText(""); + tags_table->item(row, 1)->setText({}); QTableWidgetItem* value_item = tags_table->item(row, 1); value_item->setFlags(value_item->flags() & ~Qt::ItemIsEnabled); } @@ -241,7 +241,7 @@ void TagsWidget::cellChange(int row, int column) if (value.isEmpty() && old_key.isEmpty()) { // New key, empty value - dont insert yet - tags_table->item(row, 0)->setData(Qt::UserRole, "ABOUT TO INSERT NEW VALUE"); + tags_table->item(row, 0)->setData(Qt::UserRole, QLatin1String("ABOUT TO INSERT NEW VALUE")); tags_table->setCurrentCell(row, 1); } else diff --git a/src/gui/widgets/template_list_widget.cpp b/src/gui/widgets/template_list_widget.cpp index 16083183d..53d21e369 100644 --- a/src/gui/widgets/template_list_widget.cpp +++ b/src/gui/widgets/template_list_widget.cpp @@ -95,7 +95,10 @@ TemplateListWidget::TemplateListWidget(Map* map, MapView* main_view, MapEditorCo , mobile_mode(controller->isInMobileMode()) , name_column(3) { - setWhatsThis("See more"); + Q_ASSERT(main_view); + Q_ASSERT(controller); + + setWhatsThis(Util::makeWhatThis("templates.html#setup")); QStyleOption style_option(QStyleOption::Version, QStyleOption::SO_DockWidget); @@ -109,7 +112,7 @@ TemplateListWidget::TemplateListWidget(Map* map, MapView* main_view, MapEditorCo if (mobile_mode) { - auto close_action = new QAction(QIcon(":/images/close.png"), MainWindow::tr("Close"), this); + auto close_action = new QAction(QIcon(QString::fromLatin1(":/images/close.png")), MainWindow::tr("Close"), this); connect(close_action, &QAction::triggered, this, &TemplateListWidget::closeClicked ); auto close_button = new QToolButton(); @@ -149,7 +152,7 @@ TemplateListWidget::TemplateListWidget(Map* map, MapView* main_view, MapEditorCo } else { - template_table->setHorizontalHeaderLabels(QStringList() << QString::null << tr("Opacity") << tr("Group") << tr("Filename")); + template_table->setHorizontalHeaderLabels(QStringList() << QString{} << tr("Opacity") << tr("Group") << tr("Filename")); template_table->horizontalHeaderItem(0)->setData(Qt::ToolTipRole, tr("Show")); header_view->setSectionResizeMode(0, QHeaderView::Fixed); @@ -194,10 +197,10 @@ TemplateListWidget::TemplateListWidget(Map* map, MapView* main_view, MapEditorCo QMenu* new_button_menu = new QMenu(this); if (!mobile_mode) { - new_button_menu->addAction(QIcon(":/images/open.png"), tr("Open..."), this, SLOT(openTemplate())); + new_button_menu->addAction(QIcon(QString::fromLatin1(":/images/open.png")), tr("Open..."), this, SLOT(openTemplate())); new_button_menu->addAction(controller->getAction("reopentemplate")); } - duplicate_action = new_button_menu->addAction(QIcon(":/images/tool-duplicate.png"), tr("Duplicate"), this, SLOT(duplicateTemplate())); + duplicate_action = new_button_menu->addAction(QIcon(QString::fromLatin1(":/images/tool-duplicate.png")), tr("Duplicate"), this, SLOT(duplicateTemplate())); #if 0 current_action = new_button_menu->addAction(tr("Sketch")); current_action->setDisabled(true); @@ -205,19 +208,19 @@ TemplateListWidget::TemplateListWidget(Map* map, MapView* main_view, MapEditorCo current_action->setDisabled(true); #endif - QToolButton* new_button = newToolButton(QIcon(":/images/plus.png"), tr("Add template...")); + QToolButton* new_button = newToolButton(QIcon(QString::fromLatin1(":/images/plus.png")), tr("Add template...")); new_button->setPopupMode(QToolButton::InstantPopup); new_button->setMenu(new_button_menu); - delete_button = newToolButton(QIcon(":/images/minus.png"), (tr("Remove"), tr("Close"))); /// \todo Use "Remove instead of "Close" + delete_button = newToolButton(QIcon(QString::fromLatin1(":/images/minus.png")), (tr("Remove"), tr("Close"))); /// \todo Use "Remove instead of "Close" SegmentedButtonLayout* add_remove_layout = new SegmentedButtonLayout(); add_remove_layout->addWidget(new_button); add_remove_layout->addWidget(delete_button); - move_up_button = newToolButton(QIcon(":/images/arrow-up.png"), tr("Move Up")); + move_up_button = newToolButton(QIcon(QString::fromLatin1(":/images/arrow-up.png")), tr("Move Up")); move_up_button->setAutoRepeat(true); - move_down_button = newToolButton(QIcon(":/images/arrow-down.png"), tr("Move Down")); + move_down_button = newToolButton(QIcon(QString::fromLatin1(":/images/arrow-down.png")), tr("Move Down")); move_down_button->setAutoRepeat(true); SegmentedButtonLayout* up_down_layout = new SegmentedButtonLayout(); @@ -225,16 +228,16 @@ TemplateListWidget::TemplateListWidget(Map* map, MapView* main_view, MapEditorCo up_down_layout->addWidget(move_down_button); // TODO: Fix string - georef_button = newToolButton(QIcon(":/images/grid.png"), tr("Georeferenced: %1").remove(": %1")); + georef_button = newToolButton(QIcon(QString::fromLatin1(":/images/grid.png")), tr("Georeferenced: %1").remove(QLatin1String(": %1"))); georef_button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); georef_button->setCheckable(true); georef_button->setChecked(true); georef_button->setEnabled(false); // TODO - move_by_hand_action = new QAction(QIcon(":/images/move.png"), tr("Move by hand"), this); + move_by_hand_action = new QAction(QIcon(QString::fromLatin1(":/images/move.png")), tr("Move by hand"), this); move_by_hand_action->setCheckable(true); move_by_hand_button = newToolButton(move_by_hand_action->icon(), move_by_hand_action->text()); move_by_hand_button->setDefaultAction(move_by_hand_action); - adjust_button = newToolButton(QIcon(":/images/georeferencing.png"), tr("Adjust...")); + adjust_button = newToolButton(QIcon(QString::fromLatin1(":/images/georeferencing.png")), tr("Adjust...")); adjust_button->setCheckable(true); QMenu* edit_menu = new QMenu(this); @@ -242,7 +245,7 @@ TemplateListWidget::TemplateListWidget(Map* map, MapView* main_view, MapEditorCo position_action->setCheckable(true); import_action = edit_menu->addAction(tr("Import and remove"), this, SLOT(importClicked())); - edit_button = newToolButton(QIcon(":/images/settings.png"), MapEditorController::tr("&Edit").remove(QChar('&'))); + edit_button = newToolButton(QIcon(QString::fromLatin1(":/images/settings.png")), MapEditorController::tr("&Edit").remove(QLatin1Char('&'))); edit_button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); edit_button->setPopupMode(QToolButton::InstantPopup); edit_button->setMenu(edit_menu); @@ -268,11 +271,11 @@ TemplateListWidget::TemplateListWidget(Map* map, MapView* main_view, MapEditorCo style()->pixelMetric(QStyle::PM_LayoutBottomMargin, &style_option) / 2 ); all_buttons_layout->addWidget(list_buttons_group); - all_buttons_layout->addWidget(new QLabel(" "), 1); + all_buttons_layout->addWidget(new QLabel(QString::fromLatin1(" ")), 1); if (!mobile_mode) { - QToolButton* help_button = newToolButton(QIcon(":/images/help.png"), tr("Help")); + QToolButton* help_button = newToolButton(QIcon(QString::fromLatin1(":/images/help.png")), tr("Help")); help_button->setAutoRaise(true); all_buttons_layout->addWidget(help_button); connect(help_button, &QAbstractButton::clicked, this, &TemplateListWidget::showHelp); @@ -282,13 +285,13 @@ TemplateListWidget::TemplateListWidget(Map* map, MapView* main_view, MapEditorCo setLayout(all_templates_layout); - //group_button = new QPushButton(QIcon(":/images/group.png"), tr("(Un)group")); + //group_button = new QPushButton(QIcon(QString::fromLatin1(":/images/group.png")), tr("(Un)group")); /*more_button = new QToolButton(); more_button->setText(tr("More...")); more_button->setPopupMode(QToolButton::InstantPopup); more_button->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed)); QMenu* more_button_menu = new QMenu(more_button); - more_button_menu->addAction(QIcon(":/images/window-new.png"), tr("Numeric transformation window")); + more_button_menu->addAction(QIcon(QString::fromLatin1(":/images/window-new.png")), tr("Numeric transformation window")); more_button_menu->addAction(tr("Set transparent color...")); more_button_menu->addAction(tr("Trace lines...")); more_button->setMenu(more_button_menu);*/ @@ -332,7 +335,7 @@ QToolButton* TemplateListWidget::newToolButton(const QIcon& icon, const QString& button->setToolTip(text); button->setIcon(icon); button->setText(text); - button->setWhatsThis("See more"); + button->setWhatsThis(Util::makeWhatThis("templates.html#setup")); return button; } @@ -370,7 +373,7 @@ void TemplateListWidget::addTemplateAt(Template* new_template, int pos) std::unique_ptr