QGIS是一套開(kāi)源的跨平臺(tái)地理信息系統(tǒng)柒瓣,支持的操作系統(tǒng)包括Windows、Mac吠架、Linux和BSD芙贫,也即將支持Android。當(dāng)前軟件的最新版本為2.18傍药,文檔版本為2.14(2.16版正在更新磺平,2.18遙遙無(wú)期)。
基礎(chǔ)功能
地圖展示
QGIS支持柵格(raster)和矢量(vector)兩種圖像拐辽,前者主要包括GeoTIFF拣挪、JPEG、PNG等文件格式俱诸,后者以點(diǎn)菠劝、折線和多邊形三種要素(feature)的形式進(jìn)行存儲(chǔ),既可以是文件睁搭,也可以是數(shù)據(jù)庫(kù)赶诊。
柵格圖即是點(diǎn)陣圖笼平,用于展示衛(wèi)星遙感、土地利用舔痪、溫度分布等直觀影像出吹。矢量圖通常用于展示人為劃分的功能性邏輯區(qū)域,比如用點(diǎn)表示城市辙喂、機(jī)場(chǎng)捶牢、加油站等不同級(jí)別的地點(diǎn)信息,用折線表示道路巍耗、河流等線型信息秋麸,用多邊形表示湖泊、各類用地等區(qū)域信息炬太。
在QGIS中導(dǎo)入矢量圖后灸蟆,可以通過(guò)鼠標(biāo)操作對(duì)其直接進(jìn)行修改(比如增加點(diǎn)或線段、拖動(dòng)多邊形頂點(diǎn)等)亲族,也可以用相同的方式根據(jù)項(xiàng)目需要?jiǎng)?chuàng)建自己的矢量圖炒考。
矢量圖的展示效果有很大的調(diào)整空間,可以設(shè)置顏色霎迫、透明度斋枢、紋理、寬度知给、大小等屬性瓤帚,可以顯示說(shuō)明性文字或標(biāo)簽(如路名),更強(qiáng)大的是涩赢,矢量圖中的每一個(gè)要素除了坐標(biāo)信息以外戈次,還可以具有任意多的屬性值,用于記錄如道路類別筒扒、建筑用途怯邪、區(qū)域面積等諸多額外信息,通過(guò)編寫(xiě)條件腳本花墩,可以利用這些屬性值實(shí)現(xiàn)如不同縮放程度下過(guò)濾顯示不同級(jí)別的要素悬秉、以不同的顏色顯示不同功能的區(qū)域等靈活的展示形式。
QGIS支持將編輯好的地圖輸出為各種格式的圖片允跑、PDF或SVG文件,可以添加網(wǎng)格、指北針聋丝、圖例索烹、比例尺等多種裝飾信息,以制作有模有樣的實(shí)用地圖弱睦。
空間分析
QGIS提供了強(qiáng)大的空間分析能力百姓,除了自帶的工具以外,還可以通過(guò)插件的形式進(jìn)行擴(kuò)展况木,同時(shí)集成了GRASS(Geographic Resources Analysis Support System)的400多項(xiàng)功能模塊垒拢。
空間分析旨在挖掘地圖中的有用信息,以得到特定問(wèn)題的求解火惊。比如針對(duì)房地產(chǎn)開(kāi)發(fā)求类,需要計(jì)算及分析區(qū)域面積、與各大交通要道的距離屹耐、地勢(shì)尸疆、居民密度等諸多影響因素,借助現(xiàn)成功能或自己編寫(xiě)腳本可以篩選出所需的最佳區(qū)域惶岭。
一個(gè)比較直觀的例子是最短路徑的計(jì)算寿弱,利用QGIS自帶的插件「Road graph plugin」可以實(shí)現(xiàn)該功能。將代表道路的圖層設(shè)置為計(jì)算依據(jù)按灶,在地圖上選擇任意兩點(diǎn)作為起點(diǎn)和終點(diǎn)症革,所得的最短路徑將以紅線標(biāo)出,同時(shí)顯示公里數(shù)和耗時(shí)兆衅。
通過(guò)條件設(shè)置地沮,還可以根據(jù)道路類別(高速、小路等)羡亩、限速等信息進(jìn)行不同使用場(chǎng)景下的道路規(guī)劃——這讓我想起了百度地圖導(dǎo)航時(shí)「用時(shí)較少」、「距離較短」危融、「高速優(yōu)先」之類的選項(xiàng)畏铆。
三維渲染
柵格圖一個(gè)重要的作用是表示包含高程信息的地形圖——數(shù)字高程模型DEM(Digital Elevation Model)。
QGIS有多種途徑可以優(yōu)化DEM的顯示效果吉殃。
■ 使用自帶功能
■ 使用插件
使用QGIS自帶的插件「Raster Terrain Analysis plugin」可以更便捷地實(shí)現(xiàn)DEM的三維渲染碉怔。
■ 使用GRASS
GRASS作為一套始于1984年的GIS撮胧,是妥妥的前輩桨踪,為QGIS所集成,其諸多工具中也有一件可以用于DEM渲染芹啥。
當(dāng)然DEM除了提供直觀的三維展示纳账,同樣可以用于空間分析,比如通過(guò)條件腳本突出顯示一定坡度范圍的區(qū)域捺疼,為房地產(chǎn)開(kāi)發(fā)(要求地勢(shì)平坦)提供參考疏虫。
數(shù)據(jù)庫(kù)
與柵格圖相比,矢量圖在諸多方面都比較靈活啤呼,在邏輯上可以將其視作包含坐標(biāo)信息和其他信息的表格卧秘。因此矢量圖除了可以以文件形式存儲(chǔ),還可以存儲(chǔ)在數(shù)據(jù)庫(kù)中官扣。存儲(chǔ)地理空間數(shù)據(jù)的數(shù)據(jù)庫(kù)翅敌,稱為空間數(shù)據(jù)庫(kù)(spatial database)。QGIS支持與Oracle Spatial惕蹄、SQL Server蚯涮、MySQL、PostgreSQL等多種主流數(shù)據(jù)庫(kù)連接卖陵,其中PostgreSQL為QGIS的主打數(shù)據(jù)庫(kù)遭顶。
PostgreSQL是一種對(duì)象-關(guān)系數(shù)據(jù)庫(kù),在傳統(tǒng)的關(guān)系數(shù)據(jù)庫(kù)中引入了面向?qū)ο蠹夹g(shù)泪蔫,以存儲(chǔ)非結(jié)構(gòu)化的空間數(shù)據(jù)——引入一種叫g(shù)eometry的鍵類型棒旗。空間數(shù)據(jù)的操作與普通數(shù)據(jù)有所不同撩荣,于是出現(xiàn)了PostGIS铣揉,作為PostgreSQL的一個(gè)擴(kuò)展,它提供了許多便捷的空間數(shù)據(jù)處理函數(shù)餐曹。
概念與操作
開(kāi)放地理空間信息聯(lián)盟OGC(Open Geospatial Consortium)制定了空間信息在數(shù)據(jù)庫(kù)中的存儲(chǔ)規(guī)格——SFS模型(Simple Feature for SQL Model)逛拱,該模型中,三種空間要素的坐標(biāo)信息有WKT(well-known text)和WKB(well-known binary)兩種表示格式台猴。其中WKT易于人類閱讀朽合,WKB是用于存儲(chǔ)和傳輸?shù)亩M(jìn)制俱两。
比如在PostGIS環(huán)境下定義一個(gè)坐標(biāo)為(1,1)的點(diǎn):
select st_pointfromtext(’POINT(1 1)’);
這里st_pointfromtext
就是PostGIS提供的函數(shù),POINT(1 1)
就是點(diǎn)的WKT表示旁舰。
所得結(jié)果(一長(zhǎng)串十六進(jìn)制碼就是點(diǎn)的WKB表示):
st_pointfromtext
--------------------------------------------
0101000000000000000000F03F000000000000F03F
(1 row)
如果希望結(jié)果顯示為WKT形式锋华,則需要用到轉(zhuǎn)換函數(shù)st_astext
:
select st_astext(st_pointfromtext(’POINT(1 1)’));
結(jié)果:
st_astext
------------
POINT(1 1)
(1 row)
在實(shí)際使用中,通常一個(gè)圖層在數(shù)據(jù)庫(kù)中用一張表表示箭窜,其中一個(gè)鍵設(shè)為geometry類型毯焕,且限定其只能賦值為「ST_Point」、「ST_LineString」或「ST_Polygon」磺樱,即一個(gè)圖層中的要素要么都是點(diǎn)纳猫,要么都是折線,要么都是多邊形竹捉。
一個(gè)插入點(diǎn)的示例(其中「4326」為坐標(biāo)參考系的代號(hào)):
insert into people (name,house_no, street_id, phone_no, the_geom)
values (’Fault Towers’,34,3,’072 812 31 28’,’SRID=4326;POINT(33 -33)’);
一個(gè)更新折線的示例:
update streets set the_geom = ’SRID=4326;LINESTRING(20 -33, 21 -34, 24 -33)’
where streets.id=2;
一個(gè)插入多邊形的示例:
insert into cities (name, the_geom)
values (’Tokyo Outer Wards’, ’SRID=4326;POLYGON((20 10, 20 20, 35 20, 20 10),(-10 -30, -5 0, -15 -15, -10 -30))’);
可見(jiàn)芜辕,無(wú)論何種類型的要素,都是以點(diǎn)為基本單位構(gòu)建的块差,多邊形要求首末兩點(diǎn)重合侵续。
導(dǎo)入與導(dǎo)出
PostGIS和QGIS提供了多種工具,以實(shí)現(xiàn)矢量圖在文件與數(shù)據(jù)庫(kù)之間的相互轉(zhuǎn)換憨闰,使得處理GIS數(shù)據(jù)時(shí)状蜗,可以兼得QGIS圖形界面之便捷與數(shù)據(jù)庫(kù)ODBC之靈活。
- shp2pgsql:將矢量圖文件導(dǎo)入數(shù)據(jù)庫(kù)的命令行工具鹉动。
- pgsql2shp:從數(shù)據(jù)庫(kù)中導(dǎo)出矢量圖文件的命令行工具轧坎。
- ogr2ogr:文件與數(shù)據(jù)庫(kù)互轉(zhuǎn)的命令行工具。
- SPIT:將矢量圖文件導(dǎo)入數(shù)據(jù)庫(kù)的QGIS插件泽示。
- DB Manager:QGIS自帶的數(shù)據(jù)庫(kù)管理工具缸血,支持文件與數(shù)據(jù)庫(kù)的互轉(zhuǎn)。
除了傳統(tǒng)數(shù)據(jù)庫(kù)的C/S模式械筛,還有一種將整套數(shù)據(jù)庫(kù)系統(tǒng)存儲(chǔ)在一個(gè)獨(dú)立文件中的做法——SQLite捎泻,號(hào)稱世界上最小的數(shù)據(jù)庫(kù)。對(duì)SQLite進(jìn)行空間數(shù)據(jù)處理能力的擴(kuò)展变姨,得到SpatiaLite族扰。QGIS支持SpatiaLite,兼得文件之便攜與數(shù)據(jù)庫(kù)之靈活定欧。
GPS
GPS數(shù)據(jù)分為路點(diǎn)(waypoint)、路線(route)怒竿、軌跡(track)三種砍鸠,路點(diǎn)表示離散的位置,路線表示計(jì)劃要走的一系列位置耕驰,軌跡表示已走過(guò)的一系列位置爷辱。在GIS中,路點(diǎn)由點(diǎn)表示,路線和軌跡由折線表示饭弓。
使用插件「GPS Tools」可實(shí)現(xiàn)與GPS設(shè)備的數(shù)據(jù)交互双饥,也可以從GPX(GPS Exchange Format)文件中導(dǎo)入GPS數(shù)據(jù)(GPX是一種用于記錄GPS數(shù)據(jù)的輕量級(jí)XML格式)。QGIS本身也支持將點(diǎn)和折線的圖層保存為GPX文件弟断。
但上述操作的數(shù)據(jù)都是靜態(tài)的咏花,QGIS還提供了實(shí)時(shí)顯示GPS信號(hào)的功能,在「GPS Information Panel」操作面板中阀趴,還可以看到經(jīng)緯度值昏翰、GPS信號(hào)強(qiáng)度、附近衛(wèi)星分布情況等諸多信息刘急。
C/S模式
QGIS除了可以操作本地?cái)?shù)據(jù)棚菊,還提供了C/S模式。QGIS客戶端向公共的或自己搭建的服務(wù)器請(qǐng)求地圖數(shù)據(jù)叔汁,QGIS服務(wù)器則將地圖項(xiàng)目發(fā)布出去统求。
常見(jiàn)的地圖數(shù)據(jù)服務(wù)有:
- WMS(Web Map Service):收到請(qǐng)求后,服務(wù)器將地圖渲染成圖片格式(如JPEG或PNG)后發(fā)送至客戶端据块,客戶端只能拖拽和縮放码邻,無(wú)法進(jìn)行修改。如果服務(wù)器上的數(shù)據(jù)有更新瑰钮,客戶端顯示的畫(huà)面也將相應(yīng)刷新冒滩。
- WMTS(Web Map Tile Service):使用瓦片技術(shù)的WMS篇恒,服務(wù)器預(yù)先將地圖渲染成一格格的小圖片,即瓦片凶杖,針對(duì)不同請(qǐng)求返回不同的瓦片組合胁艰,因此響應(yīng)時(shí)不再需要即時(shí)渲染,速度比WMS快智蝠。
- WFS(Web Feature Service):服務(wù)器將矢量圖原木原樣地發(fā)送給客戶端腾么,客戶端可以像操作本地?cái)?shù)據(jù)一樣修改地圖,但傳遞的數(shù)據(jù)量遠(yuǎn)大于WMS/WMTS杈湾,對(duì)帶寬要求之高解虱,幾乎找不到公共的WFS服務(wù)器。
WFS-T(Web Feature Service - Transactional):WFS支持從服務(wù)器上獲取矢量要素捞魁,而WFS-T,即帶事務(wù)的WFS還支持客戶端對(duì)服務(wù)器上的要素進(jìn)行增刪改离咐。
WCS(Web Coverage Service):WCS提供涉及時(shí)空信息的多維數(shù)據(jù)谱俭,如衛(wèi)星影像、土地覆蓋數(shù)據(jù)健霹、DEM等旺上。
QGIS服務(wù)器是需要與web服務(wù)器配合使用的FastCGI/CGI程序,上述這些服務(wù)本質(zhì)上響應(yīng)的都是HTTP請(qǐng)求糖埋。對(duì)于WMS宣吱,將請(qǐng)求的URL放到web瀏覽器里同樣可以刷出地圖。
服務(wù)器通過(guò)接收HTTP請(qǐng)求參數(shù)的形式瞳别,支持GetCapabilities征候、GetMap(針對(duì)WMS)、GetFeature(針對(duì)WFS)祟敛、GetCoverage(針對(duì)WCS)等多種請(qǐng)求指令疤坝,還通過(guò)其他附帶參數(shù),實(shí)現(xiàn)靈活的請(qǐng)求操作馆铁,例如用參數(shù)「MAP」指定服務(wù)器上QGIS項(xiàng)目文件的路徑跑揉,用參數(shù)「DPI」指定所得圖像的分辨率:
http://server/path/qgis_mapserv.fcgi?REQUEST=GetMap&MAP=/home/qgis/mymap.qgs&DPI=300&...
二次開(kāi)發(fā)
基于SIP和PyQT4,QGIS支持多種形式的Python二次開(kāi)發(fā)——PyQGIS埠巨,對(duì)于QGIS桌面軟件或QGIS客戶端:
QGIS啟動(dòng)時(shí)自動(dòng)運(yùn)行的腳本:編輯一個(gè)指定的.py文件历谍,用于在QGIS啟動(dòng)時(shí)執(zhí)行如清理變量「sys.path」等準(zhǔn)備工作。
在QGIS內(nèi)嵌的控制臺(tái)中執(zhí)行的語(yǔ)句:QGIS已經(jīng)為用戶做好了導(dǎo)入PyQGIS模塊等初始化工作辣垒,我們可以在控制臺(tái)里直接操作畫(huà)布望侈、菜單、工具欄等勋桶。
插件開(kāi)發(fā)
應(yīng)用程序開(kāi)發(fā):通過(guò)導(dǎo)入PyQGIS的模塊捐韩,如「qgis.core」和「qgis.gui」,就可以在我們自己的Python程序中進(jìn)行GIS數(shù)據(jù)處理鹃锈。我根據(jù)《PyQGIS Developer Cookbook》中的例子拼了一個(gè)簡(jiǎn)單的小程序——在窗口中顯示柵格圖奥帘,支持拖拽縮放和矩形涂鴉。
from qgis.gui import *
from PyQt4.QtGui import QAction, QMainWindow
from PyQt4.QtCore import SIGNAL, Qt, QFileInfo
# 自定義矩形繪制工具
class RectangleMapTool(QgsMapToolEmitPoint):
def __init__(self, canvas):
self.canvas = canvas
QgsMapToolEmitPoint.__init__(self, self.canvas)
self.rubberBand = QgsRubberBand(self.canvas, QGis.Polygon)
self.rubberBand.setColor(Qt.red)
self.rubberBand.setWidth(1)
self.reset()
def reset(self):
self.startPoint = self.endPoint = None
self.isEmittingPoint = False
self.rubberBand.reset(QGis.Polygon)
def canvasPressEvent(self, e):
self.startPoint = self.toMapCoordinates(e.pos())
self.endPoint = self.startPoint
self.isEmittingPoint = True
self.showRect(self.startPoint, self.endPoint)
def canvasReleaseEvent(self, e):
self.isEmittingPoint = False
r = self.rectangle()
if r is not None:
print "Rectangle:", r.xMinimum(), r.yMinimum(), r.xMaximum(), r.yMaximum()
def canvasMoveEvent(self, e):
if not self.isEmittingPoint:
return
self.endPoint = self.toMapCoordinates(e.pos())
self.showRect(self.startPoint, self.endPoint)
def showRect(self, startPoint, endPoint):
self.rubberBand.reset(QGis.Polygon)
if startPoint.x() == endPoint.x() or startPoint.y() == endPoint.y():
return
point1 = QgsPoint(startPoint.x(), startPoint.y())
point2 = QgsPoint(startPoint.x(), endPoint.y())
point3 = QgsPoint(endPoint.x(), endPoint.y())
point4 = QgsPoint(endPoint.x(), startPoint.y())
self.rubberBand.addPoint(point1, False)
self.rubberBand.addPoint(point2, False)
self.rubberBand.addPoint(point3, False)
self.rubberBand.addPoint(point4, True) # true to update canvas
self.rubberBand.show()
def rectangle(self):
if self.startPoint is None or self.endPoint is None:
return None
elif self.startPoint.x() == self.endPoint.x() or self.startPoint.y() == self.endPoint.y():
return None
return QgsRectangle(self.startPoint, self.endPoint)
def deactivate(self):
super(RectangleMapTool, self).deactivate()
self.emit(SIGNAL("deactivated()"))
# 定義主窗口
class MyWnd(QMainWindow):
def __init__(self, layer):
QMainWindow.__init__(self)
self.canvas = QgsMapCanvas()
self.canvas.setCanvasColor(Qt.white)
self.canvas.setExtent(layer.extent())
self.canvas.setLayerSet([QgsMapCanvasLayer(layer)])
self.setCentralWidget(self.canvas)
actionZoomIn = QAction("Zoom in", self)
actionZoomOut = QAction("Zoom out", self)
actionPan = QAction("Pan", self)
actionRectangle = QAction("Rectangle", self)
actionZoomIn.setCheckable(True)
actionZoomOut.setCheckable(True)
actionPan.setCheckable(True)
actionRectangle.setCheckable(True)
self.connect(actionZoomIn, SIGNAL("triggered()"), self.zoomIn)
self.connect(actionZoomOut, SIGNAL("triggered()"), self.zoomOut)
self.connect(actionPan, SIGNAL("triggered()"), self.pan)
self.connect(actionRectangle, SIGNAL("triggered()"), self.rectangle)
self.toolbar = self.addToolBar("Canvas actions")
self.toolbar.addAction(actionZoomIn)
self.toolbar.addAction(actionZoomOut)
self.toolbar.addAction(actionPan)
self.toolbar.addAction(actionRectangle)
# create the map tools
self.toolPan = QgsMapToolPan(self.canvas)
self.toolPan.setAction(actionPan)
self.toolZoomIn = QgsMapToolZoom(self.canvas, False) # false = in
self.toolZoomIn.setAction(actionZoomIn)
self.toolZoomOut = QgsMapToolZoom(self.canvas, True) # true = out
self.toolZoomOut.setAction(actionZoomOut)
self.toolRectangle = RectangleMapTool(self.canvas)
self.toolRectangle.setAction(actionRectangle)
self.pan()
def zoomIn(self):
self.canvas.setMapTool(self.toolZoomIn)
def zoomOut(self):
self.canvas.setMapTool(self.toolZoomOut)
def pan(self):
self.canvas.setMapTool(self.toolPan)
def rectangle(self):
self.canvas.setMapTool(self.toolRectangle)
# 將美國(guó)阿拉斯加州的地圖加載為圖層仪召,并顯示到窗口中
fileName = "D:/qgis_sample_data/raster/landcover.img"
fileInfo = QFileInfo(fileName)
baseName = fileInfo.baseName()
rlayer = QgsRasterLayer(fileName, baseName)
if not rlayer.isValid():
print "Layer failed to load!"
QgsMapLayerRegistry.instance().addMapLayer(rlayer)
w = MyWnd(rlayer)
w.show()
對(duì)于QGIS服務(wù)器扔茅,也可以用PyQGIS進(jìn)行插件和獨(dú)立程序的開(kāi)發(fā)已旧。通過(guò)插件開(kāi)發(fā),可以實(shí)現(xiàn)修改現(xiàn)有服務(wù)(WMS召娜、WFS等)运褪、根據(jù)請(qǐng)求進(jìn)行額外處理(如身份驗(yàn)證)甚至修改請(qǐng)求參數(shù)、修改響應(yīng)結(jié)果(如給圖片增加水泳寥场)秸讹、新建自定義服務(wù)、設(shè)置訪問(wèn)權(quán)限等靈活的功能雅倒。
一種應(yīng)用架構(gòu)
QGIS Client和QGIS Server都可以替換為自己開(kāi)發(fā)的PyQGIS程序璃诀。或者出于瘦客戶端的考慮蔑匣,QGIS還支持配置出簡(jiǎn)潔的用戶界面劣欢。
學(xué)習(xí)資料
2017年2月1日~6日 蘇州&無(wú)錫