当前位置:   article > 正文

QGis的使用_python module qgis gui cmakelists.txt 自定义生成已退出

python module qgis gui cmakelists.txt 自定义生成已退出

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&ltype=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=<mapbox key>

天地图矢量图: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=<tianditu key>
天地图矢量注记: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=<tianditu key>
天地图遥感图: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=<tianditu key>
天地图遥感注记: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=<tianditu key>

WMTS:
Mapbox:https://api.mapbox.com/styles/v1/mapbox/streets-v11/wmts?access_token=<mapbox key>

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 <QApplication>
#include <QString>
#include <QWidget>
#include <qgis.h>
#include <qgsapplication.h>
#include <qgsproviderregistry.h>
#include <qgssinglesymbolrendererv2.h>
#include <qgsmaplayerregistry.h>
#include <qgsvectorlayer.h>
#include <qgsmapcanvas.h>
#include <qgsgeometry.h>
#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 <qgsapplication.h>
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 <qgsproject.h>
#include <qgsvectorlayer.h>
#include <qgseditorwidgetregistry.h>

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<QgsMapLayer*> 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. 源码解析

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
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/117550
推荐阅读
相关标签
  

闽ICP备14008679号