• QGis的使用


    1. QGis编译安装

    1.1. Linux下的编译安装

    (1)下载源码

    QGis源码: https://download.qgis.org/downloads/
    官方api查询:https://api.qgis.org/api/3.28/index.html
    官方文档:https://qgis.org/en/docs/index.html#

    官方文档中点击对应的版本-》building QGis from source(查看对应的编译要求)

    QGis3.16在Ubuntu18.04(bionic)下的编译要求:qt5.9

    (2)ccache

    You should also setup ccache to speed up compile times:

    cd /usr/local/bin
    sudo ln -s /usr/bin/ccache gcc
    sudo ln -s /usr/bin/ccache g++

    or simply add /usr/lib/ccache to your PATH.

    (3)编译pyqt5

    PyQt5源码下载:http://www.riverbankcomputing.com/software/pyqt/download5
    PyQt5-sip下载:https://pypi.org/project/PyQt5-sip/

    编译:Ubuntu 14.04 64bit上安装python-pyqt5软件包(python 2.7)

    python configure.py --sip-incdir=/usr/include/python2.7
    make -j4
    sudo make install
    
    • 1
    • 2
    • 3

    sip版本一致的问题:

    sip -V
    
    #pythoy
    import sip
    print(sip.SIP_VERSION_STR)
    
    import PyQt5
    print(PyQt5.sip.SIP_VERSION_STR)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    问题:

    问题0 :"no module named pyqt5.sip"解决
    解决:PyQt5-sip在configure时须指定PyQt5.sip(不是sip的安装)
       python3 configure.py --sip-module PyQt5.sip
    sip下载地址:
       https://www.riverbankcomputing.com/static/Downloads/sip/4.19.25/sip-4.19.25.tar.gz
       https://www.riverbankcomputing.com/software/sip/download/
    PyQt5-sip下载地址:
       https://www.cnpython.com/pypi/pyqt5-sip/download
       PyQt5_sip-12.8.1.tar.gz下载地址

    问题1 :qmake: could not exec ‘/usr/lib/x86_64-linux-gnu/qt4/bin/qmake’: No such file or directory
    解决:没安装qt库,sudo apt-get install qt-sdk

    问题2 :Error: Make sure you have a working sip on your PATH or use the --sip argument to explicitly specify a working sip.
    解决:没安装sip,

    问题3:sipAPIQtCore.h:28:17: fatal error: sip.h: 没有那个文件或目录
    解决:没有指定sip.h所在路径,configure时使用 python configure.py --sip-incdir=/usr/include/python2.7

    问题4:qprinter.h: No such file or directory
    解决:第一步python configure.py命令生成各种Qt模块后,其中的QtWebKitWidgets模块由于Qt4和Qt5的qprinter.h所属模块的调整(Qt4存在于QtGui中,Qt5将其调整到QtPrintSupport中了),QtWebKitWidgets的Makefile中缺失了对QtPrintSupport的头文件目录引用,会导致后面编译PyQt5时无法找到qprinter.h头文件,编译失败(编译过程非常漫长),所以需要向刚生成的QtWebKitWidgets模块源文件的MakeFile文件的INCPATH中添加QtPrintSupport引用。
    第一种方法:修改路径
    原INCPATH为:

    INCPATH = -I/opt/Qt/5.3/gcc/mkspecs/linux-g++ -I. -I. -I/usr/include/python3.4m 
    -I/opt/Qt/5.3/gcc/include -I/opt/Qt/5.3/gcc/include/QtWebKitWidgets 
    -I/opt/Qt/5.3/gcc/include/QtWebKit -I/opt/Qt/5.3/gcc/include/QtWidgets 
    -I/opt/Qt/5.3/gcc/include/QtNetwork -I/opt/Qt/5.3/gcc/include/QtGui 
    -I/opt/Qt/5.3/gcc/include/QtCore -I.
    
    • 1
    • 2
    • 3
    • 4
    • 5

    修改为:

    INCPATH = -I/opt/Qt/5.3/gcc/mkspecs/linux-g++ -I. -I. -I/usr/include/python3.4m 
    -I/opt/Qt/5.3/gcc/include -I/opt/Qt/5.3/gcc/include/QtWebKitWidgets 
    -I/opt/Qt/5.3/gcc/include/QtWebKit -I/opt/Qt/5.3/gcc/include/QtWidgets 
    -I/opt/Qt/5.3/gcc/include/QtNetwork -I/opt/Qt/5.3/gcc/include/QtPrintSupport 
    -I/opt/Qt/5.3/gcc/include/QtGui -I/opt/Qt/5.3/gcc/include/QtCore -I.
    
    • 1
    • 2
    • 3
    • 4
    • 5

    第二种方法:直接在QtWebKitWidgets模块源文件的QtWebKitWidgets.pro文件中加入

    QT += printsupport
    
    • 1

    接下来执行编译安装:

    sudo make 
    sudo make install
    
    • 1
    • 2

    (4)编译qgis

    QGis官方编译说明
    中标麒麟下编译QGis
    linux下直接cmake编译qgis

    apt-get install 
    bison 
    ca-certificates 
    ccache 
    cmake 
    cmake-curses-gui 
    dh-python 
    doxygen 
    expect 
    flex 
    flip 
    gdal-bin 
    git 
    graphviz 
    grass-dev 
    libexiv2-dev 
    libexpat1-dev 
    libfcgi-dev 
    libgdal-dev 
    libgeos-dev 
    libgsl-dev 
    libpq-dev 
    libproj-dev 
    libprotobuf-dev 
    libqca-qt5-2-dev 
    libqca-qt5-2-plugins 
    libqscintilla2-qt5-dev 
    libqt5opengl5-dev 
    libqt5serialport5-dev 
    libqt5sql5-sqlite 
    libqt5svg5-dev 
    libqt5webkit5-dev 
    libqt5xmlpatterns5-dev 
    libqwt-qt5-dev 
    libspatialindex-dev 
    libspatialite-dev 
    libsqlite3-dev 
    libsqlite3-mod-spatialite 
    libyaml-tiny-perl 
    libzip-dev 
    lighttpd 
    locales 
    ninja-build 
    ocl-icd-opencl-dev 
    opencl-headers 
    pkg-config 
    poppler-utils 
    protobuf-compiler 
    pyqt5-dev 
    pyqt5-dev-tools 
    pyqt5.qsci-dev 
    python3-all-dev 
    python3-autopep8 
    python3-dateutil 
    python3-dev 
    python3-future 
    python3-gdal 
    python3-httplib2 
    python3-jinja2 
    python3-lxml 
    python3-markupsafe 
    python3-mock 
    python3-nose2 
    python3-owslib 
    python3-plotly 
    python3-psycopg2 
    python3-pygments 
    python3-pyproj
    python3-pyqt5 
    python3-pyqt5.qsci 
    python3-pyqt5.qtsql 
    python3-pyqt5.qtsvg 
    python3-pyqt5.qtwebkit 
    python3-requests 
    python3-sip 
    python3-sip-dev 
    python3-six 
    python3-termcolor 
    python3-tz 
    python3-yaml 
    qt3d-assimpsceneimport-plugin 
    qt3d-defaultgeometryloader-plugin 
    qt3d-gltfsceneio-plugin 
    qt3d-scene2d-plugin 
    qt3d5-dev 
    qt5-default 
    qt5keychain-dev 
    qtbase5-dev 
    qtbase5-private-dev 
    qtpositioning5-dev 
    qttools5-dev 
    qttools5-dev-tools 
    saga 
    spawn-fcgi 
    pandoc 
    xauth 
    xfonts-100dpi 
    xfonts-75dpi 
    xfonts-base 
    xfonts-scalable 
    xvfb
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    mkdir BUILD
    cd BUILD
    cmake ..
    make -j8
    sudo make install
    
    • 1
    • 2
    • 3
    • 4
    • 5

    (5)qgis_core提示无法解析外部符号

    库的原因,去掉spatialite.lib,更改为spatialite_i.lib就可以

    1.2 CMakeList.txt解析

    ##############################################################
    # 编译版本设置
    SET(CPACK_PACKAGE_VERSION_MAJOR "2")
    ……
    
    # Note the version no is Mmmpp for Major/minor/patch, 0-padded, thus '10100' for 1.1.0
    MATH(EXPR QGIS_VERSION_INT "${CPACK_PACKAGE_VERSION_MAJOR}*10000+${CPACK_PACKAGE_VERSION_MINOR}*100+${CPACK_PACKAGE_VERSION_PATCH}")
    MESSAGE(STATUS "QGIS version: ${COMPLETE_VERSION} ${RELEASE_NAME} (${QGIS_VERSION_INT})")
    
    #############################################################
    # CMake设置
    CMAKE_MINIMUM_REQUIRED(VERSION 2.8.6) # CMake最低要求
    ……
    
    # 配置GRASS插件
    FOREACH (GRASS_SEARCH_VERSION 6 7)
      ……
    
    # 下面是各种编译选项
    SET (WITH_DESKTOP TRUE CACHE BOOL "Determines whether QGIS desktop should be built")
    SET (WITH_SERVER FALSE CACHE BOOL "Determines whether QGIS server should be built")
    ……
    
    SET (WITH_CUSTOM_WIDGETS FALSE CACHE BOOL "Determines whether QGIS custom widgets for Qt Designer should be built")
    
    SET (WITH_ASTYLE FALSE CACHE BOOL "If you plan to contribute you should reindent with scripts/prepare-commit.sh (using 'our' astyle)")
    
    SET (WITH_POSTGRESQL TRUE CACHE BOOL "Determines whether POSTGRESQL support should be built")
    ……
    
    SET (WITH_INTERNAL_QEXTSERIALPORT TRUE CACHE BOOL "Use internal build of Qextserialport")
    
    SET (WITH_QSPATIALITE FALSE CACHE BOOL "Determines whether QSPATIALITE sql driver should be built")
    
    SET (WITH_ORACLE FALSE CACHE BOOL "Determines whether Oracle support should be built")
    ……
    
    # 如果你需要Python支持,关注这一块
    SET (WITH_BINDINGS TRUE CACHE BOOL "Determines whether python bindings should be built")
    IF (WITH_BINDINGS)
      ……
    ENDIF (WITH_BINDINGS)
    
    # Android移动端支持
    IF (ANDROID)
        SET (DEFAULT_WITH_QTMOBILITY TRUE)
    ELSE (ANDROID)
        SET (DEFAULT_WITH_QTMOBILITY FALSE)
    ENDIF (ANDROID)
    SET (WITH_QTMOBILITY ${DEFAULT_WITH_QTMOBILITY} CACHE BOOL "Determines if QtMobility related code should be build (for example internal GPS)")
    
    # globe三维支持
    SET (WITH_GLOBE FALSE CACHE BOOL "Determines whether Globe plugin should be built")
    ……
    
    SET (PEDANTIC TRUE CACHE BOOL "Determines if we should compile in pedantic mode.")
    SET (ENABLE_TESTS TRUE CACHE BOOL "Build unit tests?")
    SET (ENABLE_COVERAGE FALSE CACHE BOOL "Perform coverage tests?")
    SET (GENERATE_COVERAGE_DOCS FALSE CACHE BOOL "Generate coverage docs (requires lcov)?")
    
    # hide this variable because building of python bindings might fail
    # if set to other directory than expected
    MARK_AS_ADVANCED(LIBRARY_OUTPUT_PATH)
    
    # 这里是指定编译器类型
    IF (MSVC AND CMAKE_GENERATOR MATCHES "NMake")
      # following variable is also used in qgsconfig.h
      SET (USING_NMAKE TRUE)
    ENDIF (MSVC AND CMAKE_GENERATOR MATCHES "NMake")
    
    #############################################################
    # 这里是Flex和Bison
    
    INCLUDE(Flex)
    
    FIND_FLEX()
    
    IF (NOT FLEX_EXECUTABLE)
      MESSAGE(FATAL_ERROR "Couldn't find Flex")
    ENDIF (NOT FLEX_EXECUTABLE)
    
    INCLUDE(Bison)
    
    FIND_BISON()
    
    IF (NOT BISON_EXECUTABLE)
      MESSAGE(FATAL_ERROR "Couldn't find Bison")
    ENDIF (NOT BISON_EXECUTABLE)
    
    #############################################################
    # 下面就开始找依赖库了
    
    IF(NOT WIN32 AND NOT ANDROID)
      ……
    
    # 必须要的依赖库
    FIND_PACKAGE(Proj)
    FIND_PACKAGE(GEOS)
    FIND_PACKAGE(GDAL)
    FIND_PACKAGE(Expat REQUIRED)
    FIND_PACKAGE(Spatialindex REQUIRED)
    FIND_PACKAGE(Qwt REQUIRED)
    
    IF (WITH_INTERNAL_QEXTSERIALPORT)
      SET(QEXTSERIALPORT_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/src/core/gps/qextserialport)
    ELSE (WITH_INTERNAL_QEXTSERIALPORT)
      FIND_PACKAGE(Qextserialport REQUIRED)
    ENDIF(WITH_INTERNAL_QEXTSERIALPORT)
    
    FIND_PACKAGE(Sqlite3)
    IF (NOT SQLITE3_FOUND)
      MESSAGE (SEND_ERROR "sqlite3 dependency was not found!")
    ENDIF (NOT SQLITE3_FOUND)
    
    # 可选的依赖库
    IF (WITH_POSTGRESQL)
      FIND_PACKAGE(Postgres) # PostgreSQL provider
    ENDIF (WITH_POSTGRESQL)
    
    FIND_PACKAGE(SpatiaLite REQUIRED)
    
    # spatialite的版本处理
    IF(SPATIALITE_VERSION_GE_4_0_0)
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSPATIALITE_VERSION_GE_4_0_0")
    ENDIF(SPATIALITE_VERSION_GE_4_0_0)
    IF(SPATIALITE_VERSION_G_4_1_1)
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSPATIALITE_VERSION_G_4_1_1")
    ENDIF(SPATIALITE_VERSION_G_4_1_1)
    IF(SPATIALITE_HAS_INIT_EX)
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSPATIALITE_HAS_INIT_EX")
    ENDIF(SPATIALITE_HAS_INIT_EX)
    
    IF (NOT PROJ_FOUND OR NOT GEOS_FOUND OR NOT GDAL_FOUND)
      MESSAGE (SEND_ERROR "Some dependencies were not found! Proj: ${PROJ_FOUND}, Geos: ${GEOS_FOUND}, GDAL: ${GDAL_FOUND}")
    ENDIF (NOT PROJ_FOUND OR NOT GEOS_FOUND OR NOT GDAL_FOUND)
    
    IF (POSTGRES_FOUND)
      # following variable is used in qgsconfig.h
      SET (HAVE_POSTGRESQL TRUE)
    ENDIF (POSTGRES_FOUND)
    
    SET (WITH_QTWEBKIT TRUE CACHE INTERNAL "Enable QtWebkit support")
    IF (WITH_QTWEBKIT)
      ADD_DEFINITIONS(-DWITH_QTWEBKIT)
    ENDIF(WITH_QTWEBKIT)
    #############################################################
    # 找Qt4,如果设置了ENABLE_QT5会尝试去找Qt5,需要用Qt5编译的,关注这里的详细代码
    SET(QT_MIN_VERSION 4.8.0)
    SET (ENABLE_QT5 FALSE CACHE BOOL "If enabled will try to find Qt5 before looking for Qt4")
    IF (ENABLE_QT5)
      ……
    
    # 下面是模型测试
    SET(ENABLE_MODELTEST FALSE CACHE BOOL "Enable QT ModelTest (not for production)")
    
    IF (ENABLE_TESTS)
      ……
    
    #############################################################
    # C++11的支持
    # enable use of c++11 features where available
    # full c++11 support in clang 3.3+: http://clang.llvm.org/cxx_status.html
    # for Mac, this is probably Apple LLVM 4.2 (based on LLVM 3.2svn, in XCode 4.6+)
    #   or definitely Apple LLVM 5.0 (based on LLVM 3.3svn, in Xcode 5+):
    #   https://gist.github.com/yamaya/2924292
    
    IF (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
      EXECUTE_PROCESS(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
      IF (GCC_VERSION VERSION_GREATER 4.7 OR GCC_VERSION VERSION_EQUAL 4.7)
        SET(USE_CXX_11 TRUE)
        SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
      ENDIF()
    ELSEIF (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
      IF ((NOT APPLE AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "3.2")
           OR (APPLE AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "4.1"))
        SET(USE_CXX_11 TRUE)
        SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wno-error=c++11-narrowing")
      ENDIF()
    ELSEIF (MSVC AND MSVC_VERSION GREATER 1600)
      SET(USE_CXX_11 TRUE)
    ELSE()
      SET(USE_CXX_11 FALSE)
    ENDIF()
    
    #allow override keyword if available
    IF (NOT USE_CXX_11)
      ADD_DEFINITIONS("-Doverride=")
      ADD_DEFINITIONS("-Dnoexcept=")
      ADD_DEFINITIONS("-Dnullptr=0")
    ENDIF()
    
    
    #############################################################
    # 设置警告信息可用
    
    IF (PEDANTIC)
      MESSAGE (STATUS "Pedantic compiler settings enabled")
      IF(MSVC)
        ……
    
        # disable warnings
        SET(_warnings "${_warnings} /wd4100 ")  # unused formal parameters
       ……
    
    ENDIF (PEDANTIC)
    
    IF (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
      ……
    
    IF(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)")
     ……
    
    IF (CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES RelWithDebInfo)
      ……
    
    IF(MSVC)
      ……
    
    IF(ENABLE_COVERAGE)
      ……
    
    #############################################################
    # 操作系统环境指定的一些配置
    
    IF (WIN32)
      ……
    
      IF (MSVC)
        ……
    
      IF (APPLE)
        ……
    
    ENDIF (WIN32)
    
    IF (ANDROID)
        ……
    
    # 看一看这里,是配置预编译器选项需要的设置
    ADD_DEFINITIONS("-DCORE_EXPORT=${DLLIMPORT}")
    ADD_DEFINITIONS("-DGUI_EXPORT=${DLLIMPORT}")
    ADD_DEFINITIONS("-DPYTHON_EXPORT=${DLLIMPORT}")
    ADD_DEFINITIONS("-DANALYSIS_EXPORT=${DLLIMPORT}")
    ADD_DEFINITIONS("-DAPP_EXPORT=${DLLIMPORT}")
    ADD_DEFINITIONS("-DCUSTOMWIDGETS_EXPORT=${DLLIMPORT}")
    ADD_DEFINITIONS("-DSERVER_EXPORT=${DLLIMPORT}")
    
    #############################################################
    # 用户可以指定的一些QGIS配置,主要针对安装好的应用程序
    # user-changeable settings which can be used to customize
    # layout of QGIS installation
    # (default values are platform-specific)
    
    SET (QGIS_BIN_SUBDIR     ${DEFAULT_BIN_SUBDIR}     CACHE STRING "Subdirectory where executables will be installed")
    ……
    
    
    #############################################################
    # Python的一些依赖
    
    SET (ENABLE_PYTHON3 ${ENABLE_QT5} CACHE BOOL "If enabled will try to find Python 3 before looking for Python 2")
    IF(ENABLE_PYTHON3)
      SET(PYTHON_VER 3 CACHE STRING "Python version")
    ELSE(ENABLE_PYTHON3)
      SET(PYTHON_VER 2.7 CACHE STRING "Python version")
    ENDIF(ENABLE_PYTHON3)
    
    FIND_PACKAGE(PythonInterp ${PYTHON_VER} REQUIRED)
    
    #############################################################
    # Python bindings
    
    IF (WITH_BINDINGS)
      ……
    
    #############################################################
    # create qgsconfig.h
    # installed with app target
    
    CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/cmake_templates/qgsconfig.h.in ${CMAKE_BINARY_DIR}/qgsconfig.h)
    INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR})
    
    # Added by Jef to prevent python core and gui libs linking to other qgisCore and qgisGui libs
    # that may be in the same install prefix
    LINK_DIRECTORIES(${CMAKE_BINARY_DIR}/src/core ${CMAKE_BINARY_DIR}/src/gui)
    
    #############################################################
    # create qgsversion.h
    IF (EXISTS ${CMAKE_SOURCE_DIR}/.git/index)
      ……
    
    #############################################################
    # 在输出目录中添加一些子文件夹
    
    #create a variable to specify where our test data is
    #so that unit tests can use TEST_DATA_DIR to locate
    #the test data. See CMakeLists in test dirs for more info
    #TEST_DATA_DIR is also used by QgsRenderChecker currently in core
    SET (TEST_DATA_DIR "${CMAKE_CURRENT_SOURCE_DIR}/tests/testdata")
    
    ADD_SUBDIRECTORY(src)
    ADD_SUBDIRECTORY(doc)
    ADD_SUBDIRECTORY(images)
    ADD_SUBDIRECTORY(resources)
    ADD_SUBDIRECTORY(i18n)
    
    IF (WITH_BINDINGS)
      ADD_SUBDIRECTORY(python)
    ENDIF (WITH_BINDINGS)
    
    IF (ENABLE_TESTS)
      ADD_SUBDIRECTORY(tests)
      SET (CTEST_BINARY_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/output/bin" )
      MESSAGE (STATUS "Ctest Binary Directory set to: ${CTEST_BINARY_DIRECTORY}")
    ENDIF (ENABLE_TESTS)
    
    IF (APPLE)
      ……
    
    INSTALL(FILES cmake/FindQGIS.cmake DESTINATION ${QGIS_DATA_DIR})
    
    #############################################################
    # Post-install commands
    ADD_SUBDIRECTORY(postinstall)
    
    #############################################################
    # Uninstall stuff see: http://www.vtk.org/Wiki/CMake_FAQ
    CONFIGURE_FILE(
      ……
    
    #############################################################
    # Enable packaging
    ……
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333

    2. 使用

    2.1 添加xyz源

    能用的:

    //高德
    https://webst01.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}
    //google无标注
    http://gac-geo.googlecnapps.cn/maps/vt?lyrs=s&x={x}&y={y}&z={z}
    //google有标注
    http://gac-geo.googlecnapps.cn/maps/vt?lyrs=s,m&gl=CN&x={x}&y={y}&z={z}
    //google map
    http://gac-geo.googlecnapps.cn/maps/vt/lyrs=r&x={x}&y={y}&z={z}		//替换能用的
    //OSM(OpenStreetMap)
    http://a.tile.openstreetmap.org/{z}/{x}/{y}.png
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    google的地址解析:
    lyrs为瓦片类型:m-路线图,t-地形图,p-带标签的地形图,s-卫星图,y-带标签的卫星图,h-标签层(路名、地名)

    Google Maps: 
    https://mt1.google.com/vt/lyrs=r&x={x}&y={y}&z={z}					//不能用
    http://gac-geo.googlecnapps.cn/maps/vt/lyrs=r&x={x}&y={y}&z={z}		//替换能用的
    Google Satellite: 
    http://www.google.cn/maps/vt?lyrs=s@189&gl=cn&x={x}&y={y}&z={z}
    Google Satellite Hybrid: 
    https://mt1.google.com/vt/lyrs=y&x={x}&y={y}&z={z}
    Google Terrain: 
    https://mt1.google.com/vt/lyrs=t&x={x}&y={y}&z={z}
    Google Roads: 
    https://mt1.google.com/vt/lyrs=h&x={x}&y={y}&z={z}
    
    
    OpenTopoMap
    https://tile.opentopomap.org/{z}/{x}/{y}.png
    OpenStreetMap
    http://tile.openstreetmap.org/{z}/{x}/{y}.png
    Google Hybrid
    https://mt1.google.com/vt/lyrs=y&x={x}&y={y}&z={z}
    Google Satellite
    https://mt1.google.com/vt/lyrs=s&x={x}&y={y}&z={z}
    Google Road
    https://mt1.google.com/vt/lyrs=m&x={x}&y={y}&z={z}
    Bing Aerial
    http://ecn.t3.tiles.virtualearth.net/tiles/a{q}.jpeg?g=1
    高德卫星影像
    https://webst01.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}
    高德路网
    https://wprd01.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scl=2&style=8<ype=11
    
    
    //---------------------
    Google_Maps: https://mt1.google.com/vt/lyrs=r&x={x}&y={y}&z={z}
    Google_Terrain: https://mt1.google.com/vt/lyrs=t&x={x}&y={y}&z={z}
    Google_Roads:https://mt1.google.com/vt/lyrs=h&x={x}&y={y}&z={z}
    Google_Satellite: https://mt1.google.com/vt/lyrs=s&x={x}&y={y}&z={z}
    Google_Streets:https://mt1.google.com/vt/lyrs=m&x={x}&y={y}&z={z}
    
    cartocdn_dark_nolabel:http://basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png
    cartocdn_light_nolabels:http://basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}{r}.png
    cartocdn_voyager_nolabels:https://basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}.png
    
    ESRI_World_Imagery:https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}
    ESRI_World_Light_Gray_Base:https://server.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/{z}/{y}/{x}
    ESRI_World_Topo_Map:https://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}
    
    memomaps_tilegen:http://tileserver.memomaps.de/tilegen/{z}/{x}/{y}.png
    
    openstreetmap:https://tile.openstreetmap.org/{z}/{x}/{y}.png
    openstreetmap_br:https://tile.openstreetmap.bzh/br/{z}/{x}/{y}.png
    openstreetmap_cyclosm:https://a.tile-cyclosm.openstreetmap.fr/cyclosm/{z}/{x}/{y}.png
    openstreetmap_hot:https://a.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png
    
    stamen_terrain:http://a.tile.stamen.com/terrain/{z}/{x}/{y}.png
    stamen_terrain_background:http://a.tile.stamen.com/terrain-background/{z}/{x}/{y}.png
    stamen_terrain(高清):http://a.tile.stamen.com/terrain/{z}/{x}/{y}@2x.png
    stamen_watercolor:https://stamen-tiles-c.a.ssl.fastly.net/watercolor/{z}/{x}/{y}.jpg
    staman水彩图:http://a.tile.stamen.com/watercolor/{z}/{x}/{y}.jpg
    
    thunderforest_cycle:https://tile.thunderforest.com/cycle/{z}/{x}/{y}.png?apikey=
    thunderforest_pioneer:https://tile.thunderforest.com/pioneer/{z}/{x}/{y}.png?apikey=
    
    wmflabs_bw_mapnik:http://tiles.wmflabs.org/bw-mapnik/{z}/{x}/{y}.png
    
    高德:https://blog.csdn.net/ldlzhy1984/article/details/81015180
    https://blog.csdn.net/fredricen/article/details/77189453
    高德矢量图:https://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}
    高德遥感图:http://webst02.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}
    
    
    
    Mapbox底图:https://api.mapbox.com/styles/v1/mapbox/streets-v10/tiles/256/{z}/{x}/{y}?access_token=
    
    天地图矢量图:https://t6.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILECOL={x}&TILEROW={y}&TILEMATRIX={z}&tk=
    天地图矢量注记:https://t2.tianditu.gov.cn/cva_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILECOL={x}&TILEROW={y}&TILEMATRIX={z}&tk=
    天地图遥感图:https://t3.tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILECOL={x}&TILEROW={y}&TILEMATRIX={z}&tk=
    天地图遥感注记:https://t2.tianditu.gov.cn/cia_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cia&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILECOL={x}&TILEROW={y}&TILEMATRIX={z}&tk=
    
    WMTS:
    Mapbox:https://api.mapbox.com/styles/v1/mapbox/streets-v11/wmts?access_token=
    
    WFS:
    天地图:http://gisserver.tianditu.gov.cn/TDTService/wf
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83

    2.2 画图

    QGis画各种图

    3. 二次开发

    qt二次开发时的配置
    QGIS二次开发:加载XYZ Tiles形式的瓦片地图
    QGis二次开发例子

    QT       += core gui xml
    
    greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
    
    TARGET = qgisdemo
    TEMPLATE = app
    
    
    SOURCES += main.cpp# \
        #mainwindow.cpp
    
    #INCLUDEPATH += qgis-2.4.0
    #INCLUDEPATH += qgis-2.4.0\core
    #INCLUDEPATH += qgis-2.4.0\core\symbology-ng
    #INCLUDEPATH += qgis-2.4.0\analysis
    #INCLUDEPATH += qgis-2.4.0\gui
    
    INCLUDEPATH += qgis-2.4.0
    INCLUDEPATH += qgis-2.4.0/core
    INCLUDEPATH += qgis-2.4.0/core/symbology-ng
    INCLUDEPATH += qgis-2.4.0/analysis
    INCLUDEPATH += qgis-2.4.0/gui
    
    
    FORMS    += mainwindow.ui
    
    win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -llibqgis_analysis
    else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -llibqgis_analysis
    else:unix:!macx: LIBS += -L$$PWD/lib/ -llibqgis_analysis
    
    INCLUDEPATH += $$PWD/
    DEPENDPATH += $$PWD/
    
    win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -llibqgis_core
    else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -llibqgis_core
    else:unix:!macx: LIBS += -L$$PWD/lib/ -llibqgis_core
    
    INCLUDEPATH += $$PWD/
    DEPENDPATH += $$PWD/
    
    win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -llibqgis_gui
    else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -llibqgis_gui
    else:unix:!macx: LIBS += -L$$PWD/lib/ -llibqgis_gui
    
    INCLUDEPATH += $$PWD/
    DEPENDPATH += $$PWD/
    -----------------------------------
    Qt4.8.6+mingw+Qgis2.4.0基于QGis的二次开发
    https://blog.51cto.com/u_15127553/4237274
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include "mouseprocess.h"
    #include "paintprocess.h"
    int main( int argc, char *argv[] )
    {
    	QgsApplication a( argc, argv ,true);
    	//
    	//注意这三行代码须要更改路径;
    	QString myPluginsDir        ="D:/Qt/workspace/qgis-2.4.0/qgis-2.4.0/build/output/plugins";//插件路径(编译好的qgis目录下的plugins目录);
    	QString myLayerPath1         ="F:/gis/data_1_3/10m_admin_0_countries.shp";//图层路径,必须设置为你电脑里面shp文件的路径,不然打不开数据;
    	QString myLayerPath2         ="F:/gis/qgis_sample_data/shapefiles/airports.shp";//图层路径,必须设置为你电脑里面shp文件的路径,不然打不开数据;
    	//
    
    	QgsProviderRegistry::instance( myPluginsDir); //初始化插件的文件夹;
    	QgsVectorLayer * mypLayer1 = new QgsVectorLayer( myLayerPath1, "myLayer1", "ogr" ); //初始化矢量图层;
    	QgsVectorLayer * mypLayer2 = new QgsVectorLayer( myLayerPath2, "myLayer2", "ogr" ); //初始化矢量图层;
    	QgsVectorLayer * mypLayer3 = new QgsVectorLayer(); //初始化矢量图层;
    	mypLayer3->setRendererV2(QgsFeatureRendererV2::defaultRenderer(QGis::Point));
    	QgsFeatureIterator iter = mypLayer2->getFeatures();
    	QgsFeature feature;
    	while(iter.nextFeature(feature))
    	{
    		QgsGeometry *geo = feature.geometry();
    		QgsPoint point = geo->asPoint();
    		//qDebug() << point.x() << point.y() << endl;
    	}
    	for(int index = 0; index < 100; index ++)
    	{
    		QgsPoint point;
    		double xmin = -4.4802e+06;
    		double xmax = 4.61512e+06;
    		double ymin = 1.43353e+06;
    		double ymax = 6.50259e+06;
    		point.setX(xmin + (xmax - xmin) * ((double) qrand()) / RAND_MAX);
    		point.setY(ymin + (ymax - ymin) * ((double) qrand()) / RAND_MAX);
    		QgsFeature feature;
    		QgsGeometry *geo = QgsGeometry::fromPoint(point);
    		feature.setGeometry(geo);
    		mypLayer3->addFeature(feature);
    		mypLayer3->updateFeature(feature);
    		qDebug() << point.x() << point.y() << endl;
    	}
    	QList<QgsPoint> ring;
    	//-4.4802e+06 4.61512e+06 1.43353e+06 6.50259e+06
    	ring.append(QgsPoint(-4.4802e+06, 1.43353e+06));
    	ring.append(QgsPoint(4.61512e+06, 6.50259e+06));
    	ring.append(QgsPoint(2.61512e+06, 4.50259e+06));
    	//mypLayer2->addRing(ring);
    	qDebug() << mypLayer2->featureCount() << endl;
    	//QgsSingleSymbolRendererV2 *mypRenderer = new QgsSingleSymbolRendererV2( mypLayer->geometryType() );
    	QList <QgsMapCanvasLayer> myLayerSet;
    	// mypLayer->setRenderer( mypRenderer );
    	//mypLayer->setRendererV2(mypRenderer);
    	QgsMapLayerRegistry::instance()->addMapLayer( mypLayer1, true );
    	QgsMapLayerRegistry::instance()->addMapLayer( mypLayer2, true );
    	QgsMapLayerRegistry::instance()->addMapLayer( mypLayer3, true );
    	//myLayerSet.append( QgsMapCanvasLayer(mypLayer3, true ) );
    	myLayerSet.append( QgsMapCanvasLayer(mypLayer2, true ) );
    	//myLayerSet.append( QgsMapCanvasLayer(mypLayer1, true ) );
    	QgsRectangle extent = mypLayer2->extent();
    	qDebug() << extent.xMinimum() << extent.xMaximum() << extent.yMinimum() << extent.yMaximum() << endl;
    	QgsMapCanvas * mypMapCanvas = new QgsMapCanvas( 0, 0 );
    	mypMapCanvas->setExtent(mypLayer2->extent() );
    	mypMapCanvas->enableAntiAliasing( true);
    	mypMapCanvas->setCanvasColor( QColor(255, 255, 255 ) );
    	mypMapCanvas->freeze( false );
    	mypMapCanvas->setLayerSet( myLayerSet);
    	mypMapCanvas->setVisible( true );
    	mypMapCanvas->refresh();
    	mypMapCanvas->show();
    	MouseProcess *mouseProcess = new MouseProcess();
    	PaintProcess *paintProcess = new PaintProcess();
    	QObject::connect(mypMapCanvas, SIGNAL(xyCoordinates(QgsPoint)), 
    					 mouseProcess, SLOT(xyCoordinates(QgsPoint)));
    	QObject::connect(mypMapCanvas, SIGNAL(renderComplete(QPainter*)), 
    					 paintProcess, SLOT(renderComplete(QPainter*)));
    
    	return a.exec();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89

    验证QGis的代码:
    QGIS二次开发2–读取qgis工程文件并显示

    //pro中引入 qgis_core.lib qgis_gui.lib
    #include "mainwindow.h"
    #include 
    int main(int argc char *argv[])
    {
    	QgsApplication a(argc, argv, true);
    	QgsApplication::setPrefixPath("C:/OSGeo4W64/apps/qgis", true);
    	QgsApplication::initQgis();
    	MainWindow w;
    	w.show();
    	return a.exec();
    }
    
    // maiwindow.cpp
    #include 
    #include 
    #include 
    
    mapCanvas = new QgsMapCanvas(this);
    ui->verticalLayout->addWidget(mapCanvas);
    
    QString str = QString("d:/course/test.qgz");
    QgsProject::instance()->read(str);
    QVector<QgsVectorLayer*> vecLayers = QgsProject::instance()->layers<QgsVectorLayer*>();
    qDebug()<<vecLayers.count();
    
    //QList layers;
    //layers.append(vecLayers[0]);
    //mapCanvas->setLayers(layers);
    
    QgsEditorWidgetRegistry a;
    a.initEditors(mapCanvas);
    bridge = new QgsLayerTreeMapCanvasBridge(QgsProject::instance()->layerTreeRoot(), mapCanvas, this);
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    4. 源码解析

    QGis编码标准

    4.1 源码目录

    文件名说明
    ci
    cmake工程组织说明文件,主要是依赖库的配置说明
    cmake_templatescmake模板文件
    debianLinux操作系统所需
    doc帮助文档
    !18n翻译所需文件
    images图片资源文件
    mac苹果Mac操作系统所需
    ms-windows微软Windows操作系统所需
    postinstall软件安装完成之后执行的脚本操作
    pythonpython脚本支持
    resources各种资源、配置文件
    rpm默认配置文件
    scripts各种脚本
    src源代码,这个是我们关注的重点
    tests各种测试代码
    tools目前这里面只有一个Qt3迁移到Qt4的工具

    src文件夹下的主要内容:

    文件名说明
    3d3d要用的
    analysis工程组织说明文件,主要是依赖库的配置说明
    appcmake模板文件
    authLinux操作系统所需
    core帮助文档
    crashhandler翻译所需文件
    crssync图片资源文件
    customwidgets苹果Mac操作系统所需
    gui微软Windows操作系统所需
    native软件安装完成之后执行的脚本操作
    pluginspython脚本支持
    process各种资源、配置文件
    providers默认配置文件
    python各种脚本
    quickgui源代码,这个是我们关注的重点
    server各种测试代码
    test各种测试代码
    ui目前这里面只有一个Qt3迁移到Qt4的工具
    /app/main.cpp    			主程序
    /app/qgisapp.cpp			主窗体
    
    /core/qgsmaplayer.cpp		图层类QgsMapLayer
    /core/qgsmaptopixel.cpp		转像素坐标QgsMapToPixel
    /core/qgstiledownloadmanager.cpp 瓦片下载管理
    /core/vectortile/qgsvectortileloader.cpp		矢量瓦片加载
    /core/vectortile/qgsvectortilelayer.cpp			矢量瓦片图层
    /core/vectortile/qgsvectortilebasicrenderer.cpp 矢量瓦片渲染
    /core/network/qgsblockingnetworkrequest.cpp
    
    /gui/qgsbrowserdockwidget.cpp	浏览Dock窗体QgsBrowserDockWidget
    /gui/qgsbrowserwidget.cpp		浏览Dock中的主窗体
    /gui/qgslayertreeview.cpp		图层树控件
    /gui/qgsmapcanvas.cpp			地图画布QgsMapCanvas
    /gui/qgsmapcanvasitem.cpp		item类 QgsMapCanvasItem
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
     QgsDockWidget *mLayerTreeDock		//图层的DockWidget
     QgsStatusBar  *mStatusBar			//状态栏
    //鼠标坐标的实时显示的流程(从canvas到edit)
    QgsMapCanvas::mouseMoveEvent( QMouseEvent *e )
    	mCursorPoint = getCoordinateTransform()->toMapCoordinates( mCanvasProperties->mouseLastXY );
        emit xyCoordinates( mCursorPoint );
    QgsStatusBarCoordinatesWidget::setMapCanvas( QgsMapCanvas *mapCanvas )
    	connect( mMapCanvas, &QgsMapCanvas::xyCoordinates, this, &QgsStatusBarCoordinatesWidget::showMouseCoordinates );
      	connect( mMapCanvas, &QgsMapCanvas::extentsChanged, this, &QgsStatusBarCoordinatesWidget::showExtent );
    QgsStatusBarCoordinatesWidget::showMouseCoordinates( const QgsPointXY &p )
      	mLastCoordinate = p;
      	updateCoordinateDisplay();
    QgsStatusBarCoordinatesWidget::updateCoordinateDisplay()
        mLineEdit->setText( QgsCoordinateUtils::formatCoordinateForProject( QgsProject::instance(), mLastCoordinate, mMapCanvas->mapSettings().destinationCrs(),
                            static_cast< int >( mMousePrecisionDecimalPlaces ) ) );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    4.2 主程序main()

    位置:/src/app/main.cpp

    //这是基于MainWindow的
    QgisApp *qgis = new QgisApp( mypSplash, myRestorePlugins, mySkipBadLayers, mySkipVersionCheck, rootProfileFolder, profileName ); 
    qgis->show();
    qgis->completeInitialization();
    
    • 1
    • 2
    • 3
    • 4

    4.3 图层操作

    qgis图层操作源码

    /*
     * +--------+                +------+                 +---------+
     * |  DATA  |                |  RAW |                 | DECODED |
     * |        | --> LOADER --> |      | --> DECODER --> |         | --> RENDERER
     * | SOURCE |                | TILE |                 |  TILE   |
     * +--------+                +------+                 +---------+
     *           QgsVectorTileLoader    QgsVectorTileDecoder         QgsVectorTileBasicRenderer
     * 
     * Data source is a place from where tiles are fetched from (URL for HTTP access, local
     * files, MBTiles file, GeoPackage file or others. Loader (QgsVectorTileLoader) class
     * takes care of loading data from the data source. The "raw tile" data is just a blob
     * (QByteArray) that is encoded in some way. There are multiple ways how vector tiles
     * are encoded just like there are different formats how to store images. For example,
     * tiles can be encoded using Mapbox Vector Tiles (MVT) format or in GeoJSON. Decoder
     * (QgsVectorTileDecoder) takes care of decoding raw tile data into QgsFeature objects.
     * A decoded tile is essentially an array of vector features for each sub-layer found
     * in the tile - this is what vector tile renderer (QgsVectorTileRenderer) expects
     * and does the map rendering.
     */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    /core/vector/qgsvectorlayer.h   矢量图层
    /core/vectortile/qgsvectortilelayer.cpp		矢量瓦片图层
    
    • 1
    • 2
    QgsVectorTileLayerRenderer::render()
    {
    
    }
    
    • 1
    • 2
    • 3
    • 4

    4.5 瓦片下载

    //底层请求(最终调用)------
    QgsTileDownloadManagerReply *QgsTileDownloadManager::get( const QNetworkRequest &request )
    {
    	QgsTileDownloadManager::QueueEntry entry = findEntryForRequest( request );
    	if ( !entry.isValid() )
    	{
    		QgsDebugMsgLevel( QStringLiteral( "Tile download manager: get (new entry): " ) + request.url().toString(), 2 );
    		// create a new entry and add it to queue
    		entry.request = request;
    		entry.objWorker = new QgsTileDownloadManagerReplyWorkerObject( this, request );
    		entry.objWorker->moveToThread( mWorkerThread );
    		
    		QObject::connect( entry.objWorker, &QgsTileDownloadManagerReplyWorkerObject::finished, reply, &QgsTileDownloadManagerReply::requestFinished ); 
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    QgsMapToolIdentify::identify( const QgsGeometry &geometry, IdentifyMode mode, const QList<QgsMapLayer *> &layerList, LayerType layerType, const QgsIdentifyContext &identifyContext )
    {
    	for ( int i = 0; i < layerCount; i++ )
        {
    	    QgsMapLayer *layer = targetLayers.value( i );
    	    if ( identifyLayer( &results, layer,  mLastGeometry, mLastExtent, mLastMapUnitsPerPixel, layerType, identifyContext ) )
    	    {
    	    	if ( mode == TopDownStopAtFirst )
    	       		break;
    	    }
        }
    }
    QgsMapToolIdentify::identifyLayer( QList<IdentifyResult> *results, QgsMapLayer *layer, const QgsGeometry &geometry, const QgsRectangle &viewExtent, double mapUnitsPerPixel, QgsMapToolIdentify::LayerType layerType, const QgsIdentifyContext &identifyContext )
    {
    	if ( layer->type() == QgsMapLayerType::RasterLayer && layerType.testFlag( RasterLayer ) )
    	{
    	  	return identifyRasterLayer( results, qobject_cast<QgsRasterLayer *>( layer ), geometry, viewExtent, mapUnitsPerPixel, identifyContext );
    	}
    	else if ( layer->type() == QgsMapLayerType::VectorLayer && layerType.testFlag( VectorLayer ) )
    	{
    	  	return identifyVectorLayer( results, qobject_cast<QgsVectorLayer *>( layer ), geometry, identifyContext );
    	}
    	else if ( layer->type() == QgsMapLayerType::MeshLayer && layerType.testFlag( MeshLayer ) )
    	{
    	  	return identifyMeshLayer( results, qobject_cast<QgsMeshLayer *>( layer ), geometry, identifyContext );
    	}
    	else if ( layer->type() == QgsMapLayerType::VectorTileLayer && layerType.testFlag( VectorTileLayer ) )
    	{
    	  	return identifyVectorTileLayer( results, qobject_cast<QgsVectorTileLayer *>( layer ), geometry, identifyContext );
    	}
    	else if ( layer->type() == QgsMapLayerType::PointCloudLayer && layerType.testFlag( PointCloudLayer ) )
    	{
    	  	return identifyPointCloudLayer( results, qobject_cast<QgsPointCloudLayer *>( layer ), geometry, identifyContext );
    	}
    	else
    	{
    	  	return false;
    	}
    }
    QgsMapToolIdentify::identifyVectorTileLayer( QList<QgsMapToolIdentify::IdentifyResult> *results, QgsVectorTileLayer *layer, const QgsGeometry &geometry, const QgsIdentifyContext &identifyContext )
    {
    	const int tileZoom = layer->tileMatrixSet().scaleToZoomLevel( mCanvas->scale() );
    	const QgsTileMatrix tileMatrix = layer->tileMatrixSet().tileMatrix( tileZoom );
    	const QgsTileRange tileRange = tileMatrix.tileRangeFromExtent( r );
    	
    	for ( int row = tileRange.startRow(); row <= tileRange.endRow(); ++row )
    	{
    		for ( int col = tileRange.startColumn(); col <= tileRange.endColumn(); ++col )
    	  	{
    	    	QgsTileXYZ tileID( col, row, tileZoom );
    	    	QByteArray data = layer->getRawTile( tileID );	//图层获取瓦片(见下)
    	    	if ( data.isEmpty() )
    	      		continue;  // failed to get data
    	
    	    	QgsVectorTileMVTDecoder decoder( layer->tileMatrixSet() );
    	    	if ( !decoder.decode( tileID, data ) )
    	      		continue;  // failed to decode
    	
    	   	 	QMap<QString, QgsFields> perLayerFields;
    	    	const QStringList layerNames = decoder.layers();
    	    	for ( const QString &layerName : layerNames )
    	    	{
    	      		QSet<QString> fieldNames = qgis::listToSet( decoder.layerFieldNames( layerName ) );
    	      		perLayerFields[layerName] = QgsVectorTileUtils::makeQgisFields( fieldNames );
    	    	}
    	
    	    	const QgsVectorTileFeatures features = decoder.layerFeatures( perLayerFields, QgsCoordinateTransform() );
    	    	const QStringList featuresLayerNames = features.keys();
    	    	for ( const QString &layerName : featuresLayerNames )
    	    	{
    	      		const QgsFields fFields = perLayerFields[layerName];
    	      		const QVector<QgsFeature> &layerFeatures = features[layerName];
    	      		for ( const QgsFeature &f : layerFeatures )
    	      		{
    	        		if ( f.geometry().intersects( r ) && ( !selectionGeomPrepared || selectionGeomPrepared->intersects( f.geometry().constGet() ) ) )
    	        		{
    	          			QMap< QString, QString > derivedAttributes = commonDerivedAttributes;
    	          			derivedAttributes.insert( tr( "Feature ID" ), FID_TO_STRING( f.id() ) );
    	
    	          			results->append( IdentifyResult( layer, layerName, fFields, f, derivedAttributes ) );
    	
    	          			featureCount++;
    	        		}
    	      		}
    	    	}
    	  	}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    //图层选择
    QgsVectorTileLayer::selectByGeometry( const QgsGeometry &geometry, const QgsSelectionContext &context, Qgis::SelectBehavior behavior, Qgis::SelectGeometryRelationship relationship, Qgis::SelectionFlags flags, QgsRenderContext *renderContext )
    {
    	for ( int row = tileRange.startRow(); row <= tileRange.endRow(); ++row )
    	{
    		for ( int col = tileRange.startColumn(); col <= tileRange.endColumn(); ++col )
    		{
    			QgsTileXYZ tileID( col, row, tileZoom );
    			QByteArray data = getRawTile( tileID );
    			...
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    //矢量图层获取瓦片
    QByteArray QgsVectorTileLayer::getRawTile( QgsTileXYZ tileID )
    {
      const QgsTileMatrix tileMatrix = mMatrixSet.tileMatrix( tileID.zoomLevel() );
      const QgsTileRange tileRange( tileID.column(), tileID.column(), tileID.row(), tileID.row() );
    
      QgsDataSourceUri dsUri;
      dsUri.setEncodedUri( mDataSource );
      const QString authcfg = dsUri.authConfigId();
    
      QList<QgsVectorTileRawData> rawTiles = QgsVectorTileLoader::blockingFetchTileRawData( mSourceType, mSourcePath, tileMatrix, QPointF(), tileRange, authcfg, dsUri.httpHeaders() );
      if ( rawTiles.isEmpty() )
        return QByteArray();
      return rawTiles.first().data;
    }
    //矢量加载器阻塞下载
    QList<QgsVectorTileRawData> QgsVectorTileLoader::blockingFetchTileRawData( const QString &sourceType, const QString &sourcePath, const QgsTileMatrix &tileMatrix, const QPointF &viewCenter, const QgsTileRange &range, const QString &authid, const QgsHttpHeaders &headers, QgsFeedback *feedback )
    {
    	for ( QgsTileXYZ id : std::as_const( tiles ) )
    	{
    		if ( feedback && feedback->isCanceled() )
    			return rawTiles;
    		//三种下载方式:网络下载、MB瓦片下载、Vtpk下载
    		QByteArray rawData = isUrl ? loadFromNetwork( id, tileMatrix, sourcePath, authid, headers, feedback )
    		                     : ( mbReader ? loadFromMBTiles( id, *mbReader ) : loadFromVtpk( id, *vtpkReader ) );
    		if ( !rawData.isEmpty() )
    		{
    		 	rawTiles.append( QgsVectorTileRawData( id, rawData ) );
    		}
    	}
    }
    //网络下载
    QByteArray QgsVectorTileLoader::loadFromNetwork( const QgsTileXYZ &id, const QgsTileMatrix &tileMatrix, const QString &requestUrl, const QString &authid, const QgsHttpHeaders &headers, QgsFeedback *feedback )
    {
    	QgsBlockingNetworkRequest req;			//阻塞请求
    	req.setAuthCfg( authid ); 
    	QgsBlockingNetworkRequest::ErrorCode errCode = req.get( nr, false, feedback );  
    	QgsNetworkReplyContent reply = req.reply(); 
    	return reply.content();
    }
    //阻塞式网络请求
    QgsBlockingNetworkRequest::get( QNetworkRequest &request, bool forceRefresh, QgsFeedback *feedback )
    {
      return doRequest( Get, request, forceRefresh, feedback );
    }
    QgsBlockingNetworkRequest::doRequest( QgsBlockingNetworkRequest::Method method, QNetworkRequest &request, bool forceRefresh, QgsFeedback *feedback )
    {
    	const std::function<void()> downloaderFunction = [ this, request, &waitConditionMutex, &authRequestBufferNotEmpty, &threadFinished, &success, requestMadeFromMainThread ]()
    	{
    		// this function will always be run in worker threads -- either the blocking call is being made in a worker thread,
    		// or the blocking call has been made from the main thread and we've fired up a new thread for this function
    		Q_ASSERT( QThread::currentThread() != QgsApplication::instance()->thread() );		
    		QgsNetworkAccessManager::instance( Qt::DirectConnection );		
    		success = true;		
    		sendRequestToNetworkAccessManager( request );	//执行请求(见下)
    		
    		if ( mFeedback )
    		 	connect( mFeedback, &QgsFeedback::canceled, mReply, &QNetworkReply::abort );
    		 			
    		if ( !mAuthCfg.isEmpty() && !QgsApplication::authManager()->updateNetworkReply( mReply, mAuthCfg ) )
    		{
    			mErrorCode = NetworkError;
    			mErrorMessage = errorMessageFailedAuth();
    			QgsMessageLog::logMessage( mErrorMessage, tr( "Network" ) );
    			if ( requestMadeFromMainThread )
    			 	authRequestBufferNotEmpty.wakeAll();
    			success = false;
    		}
    		else
    		{
    			// We are able to use direct connection here, because we
    			// * either run on the thread mReply lives in, so DirectConnection is standard and safe anyway
    			// * or the owner thread of mReply is currently not doing anything because it's blocked in future.waitForFinished() (if it is the main thread)
    			connect( mReply, &QNetworkReply::finished, this, &QgsBlockingNetworkRequest::replyFinished, Qt::DirectConnection );
    			connect( mReply, &QNetworkReply::downloadProgress, this, &QgsBlockingNetworkRequest::replyProgress, Qt::DirectConnection );
    			connect( mReply, &QNetworkReply::uploadProgress, this, &QgsBlockingNetworkRequest::replyProgress, Qt::DirectConnection );
    			
    			auto resumeMainThread = [&waitConditionMutex, &authRequestBufferNotEmpty ]()
    			{
    			  // when this method is called we have "produced" a single authentication request -- so the buffer is now full
    			  // and it's time for the "consumer" (main thread) to do its part
    			  waitConditionMutex.lock();
    			  authRequestBufferNotEmpty.wakeAll();
    			  waitConditionMutex.unlock();
    			
    			  // note that we don't need to handle waking this thread back up - that's done automatically by QgsNetworkAccessManager
    			};
    			
    			if ( requestMadeFromMainThread )
    			{
    			  connect( QgsNetworkAccessManager::instance(), &QgsNetworkAccessManager::authRequestOccurred, this, resumeMainThread, Qt::DirectConnection );
    			  connect( QgsNetworkAccessManager::instance(), &QgsNetworkAccessManager::proxyAuthenticationRequired, this, resumeMainThread, Qt::DirectConnection );
    			
    			#ifndef QT_NO_SSL
    			  connect( QgsNetworkAccessManager::instance(), &QgsNetworkAccessManager::sslErrorsOccurred, this, resumeMainThread, Qt::DirectConnection );
    			#endif
    			 }
    			 QEventLoop loop;
    			 // connecting to aboutToQuit avoids an on-going request to remain stalled
    			 // when QThreadPool::globalInstance()->waitForDone()
    			 // is called at process termination
    			 connect( qApp, &QCoreApplication::aboutToQuit, &loop, &QEventLoop::quit, Qt::DirectConnection );
    			 connect( this, &QgsBlockingNetworkRequest::finished, &loop, &QEventLoop::quit, Qt::DirectConnection );
    			 loop.exec();
    		} //end of else
    	};	//end of  function
    }
    QgsBlockingNetworkRequest::sendRequestToNetworkAccessManager( const QNetworkRequest &request )
    {
    	switch ( mMethod )
    	{
    		case Get:
    		  mReply = QgsNetworkAccessManager::instance()->get( request );  //instance()回头看一下,有意思
    		  break;
    		
    		case Post:
    		  mReply = QgsNetworkAccessManager::instance()->post( request, mPayloadData );
    		  break;
    		
    		case Head:
    		  mReply = QgsNetworkAccessManager::instance()->head( request );
    		  break;
    		
    		case Put:
    		  mReply = QgsNetworkAccessManager::instance()->put( request, mPayloadData );
    		  break;
    		
    		case Delete:
    		  mReply = QgsNetworkAccessManager::instance()->deleteResource( request );
    		  break;
    	};
    }
    
    //矢量瓦片加载器构造时调用了异步加载
    QgsVectorTileLoader::QgsVectorTileLoader( const QString &uri, const QgsTileMatrix &tileMatrix, const QgsTileRange &range, const QPointF &viewCenter, const QString &authid, const QgsHttpHeaders &headers, QgsFeedback *feedback )
      : mEventLoop( new QEventLoop )
      , mFeedback( feedback )
      , mAuthCfg( authid )
      , mHeaders( headers )
    { 
    	QVector<QgsTileXYZ> tiles = QgsVectorTileUtils::tilesInRange( range, tileMatrix.zoomLevel() );
    	QgsVectorTileUtils::sortTilesByDistanceFromCenter( tiles, viewCenter );
    	for ( QgsTileXYZ id : std::as_const( tiles ) )
    	{
    	  	loadFromNetworkAsync( id, tileMatrix, uri );
    	}
    }
    //异步矢量下载
    QgsVectorTileLoader::loadFromNetworkAsync( const QgsTileXYZ &id, const QgsTileMatrix &tileMatrix, const QString &requestUrl )
    {
    	 QString url = QgsVectorTileUtils::formatXYZUrlTemplate( requestUrl, id, tileMatrix );
    	 QNetworkRequest request( url );		//网络请求
    	 QgsSetRequestInitiatorClass( request, QStringLiteral( "QgsVectorTileLoader" ) );
    	 QgsSetRequestInitiatorId( request, id.toString() );
    	
    	 request.setAttribute( static_cast<QNetworkRequest::Attribute>( QNetworkRequest::User + 1 ), id.column() );
    	 request.setAttribute( static_cast<QNetworkRequest::Attribute>( QNetworkRequest::User + 2 ), id.row() );
    	 request.setAttribute( static_cast<QNetworkRequest::Attribute>( QNetworkRequest::User + 3 ), id.zoomLevel() );
    	
    	 request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
    	 request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true );
    	
    	 mHeaders.updateNetworkRequest( request );
    	
    	 if ( !mAuthCfg.isEmpty() &&  !QgsApplication::authManager()->updateNetworkRequest( request, mAuthCfg ) )
    	 {
    	   QgsMessageLog::logMessage( tr( "network request update failed for authentication config" ), tr( "Network" ) );
    	 }
    	
    	 QgsTileDownloadManagerReply *reply = QgsApplication::tileDownloadManager()->get( request );	//执行请求(见下)
    	 connect( reply, &QgsTileDownloadManagerReply::finished, this, &QgsVectorTileLoader::tileReplyFinished );
    	 mReplies << reply;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    //wms下载
    QgsWmsTiledImageDownloadHandler::QgsWmsTiledImageDownloadHandler( )
    {
    	for ( const QgsWmsProvider::TileRequest &r : constRequests )
    	{
    		QNetworkRequest request( r.url );
    		QgsSetRequestInitiatorClass( request, QStringLiteral( "QgsWmsTiledImageDownloadHandler" ) );
    		auth.setAuthorization( request );
    		request.setRawHeader( "Accept", "*/*" );
    		request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
    		request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true );
    		request.setAttribute( static_cast<QNetworkRequest::Attribute>( TileReqNo ), mTileReqNo );
    		request.setAttribute( static_cast<QNetworkRequest::Attribute>( TileIndex ), r.index );
    		request.setAttribute( static_cast<QNetworkRequest::Attribute>( TileRect ), r.rect );
    		request.setAttribute( static_cast<QNetworkRequest::Attribute>( TileRetry ), 0 );
    		//执行请求------
    		QgsTileDownloadManagerReply *reply = QgsApplication::tileDownloadManager()->get( request );
    		connect( reply, &QgsTileDownloadManagerReply::finished, this, &QgsWmsTiledImageDownloadHandler::tileReplyFinished );
    		mReplies << reply;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    4.6 qgis插件框架

    qgis插件框架
    qgis插件开发详细教程

    4.7 坐标转换

    //文件位置:/core/qgsmaptopixel.h
     QgsPointXY toMapCoordinates( double x, double y ) const SIP_PYNAME( toMapCoordinatesF )
        {
          bool invertible;
          const QTransform matrix = mMatrix.inverted( &invertible );
          assert( invertible );
          qreal mx, my;
          matrix.map( static_cast< qreal >( x ), static_cast< qreal >( y ), &mx, &my );
          return QgsPointXY( mx, my );
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    4.8 拖动

    QgsMapCanvas::mousePressEvent( QMouseEvent *e )
     	if ( mMapTool->flags() & QgsMapTool::AllowZoomRect  && 
     	     e->button() == Qt::LeftButton 					&& 
     	     e->modifiers() & Qt::ShiftModifier )
        {
            beginZoomRect( e->pos() );
        }
    QgsMapCanvas::mouseReleaseEvent( QMouseEvent *e )
    	if ( mZoomDragging && e->button() == Qt::LeftButton )		//鼠标左键拖动地图
        	endZoomRect( e->pos() );     
    QgsMapCanvas::endZoomRect( QPoint pos )
    	QgsPointXY c = mSettings.mapToPixel().toMapCoordinates( mZoomRect.center() );		//中心点geo坐标
      	zoomByFactor( sf, &c );
    QgsMapCanvas::zoomByFactor( double scaleFactor, const QgsPointXY *center, bool ignoreScaleLock )
    	setExtent( r, true );
    QgsMapCanvas::setExtent( const QgsRectangle &r, bool magnified )
    	emit extentsChanged();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
  • 相关阅读:
    山东EV多域名SSL证书可以保护几个域名
    CSDN每日一练 |『因数-数字游戏』『天然气订单』『通货膨胀-x国货币』2023-10-16
    lodash按需引入
    机器学习实操1
    CDISC SDTM IG 3.3 版本相比于 3.2版本的变化 (上)
    「JAVA面试」半年多面试了20多家中大厂,谈谈如何准备面试?
    『忘了再学』Shell基础 — 29、AWK内置变量
    前端打包项目上线-nginx
    关于安装李沐深度学习d2l包报错的解决办法(保姆教程)
    HBase学习笔记(1)—— 知识点总结
  • 原文地址:https://blog.csdn.net/pzs0221/article/details/126412140