王強(qiáng)+雷中英
摘 要: 根據(jù)開(kāi)發(fā)人員對(duì)多邊形進(jìn)行空間操作的需求,研究在開(kāi)源Leaflet的Javascript庫(kù)的基礎(chǔ)上實(shí)現(xiàn)WEBGIS前端的多邊形切割功能。給WEBGIS管理平臺(tái)提供實(shí)時(shí)在線動(dòng)態(tài)切割和動(dòng)態(tài)顯示,避免后臺(tái)切割以及軟件預(yù)處理的不必要麻煩。
關(guān)鍵詞: Leaflet; WEBGIS; 多邊形; 切割
中圖分類號(hào):TP311 文獻(xiàn)標(biāo)志碼:A 文章編號(hào):1006-8228(2017)02-45-04
0 引言
在一般場(chǎng)景中,對(duì)多邊形切割的實(shí)現(xiàn)基本由軟件操作完成或者由后臺(tái)插件提供切割接口完成,并不是在前端部分實(shí)現(xiàn)。因?yàn)榍岸擞?jì)算量巨大會(huì)產(chǎn)生不盡人意的效率問(wèn)題,也會(huì)出現(xiàn)瀏覽器崩潰、卡頓的現(xiàn)象。而近年來(lái)前端技術(shù)的發(fā)展突飛猛進(jìn),其計(jì)算能力大大提升,由此帶來(lái)其實(shí)現(xiàn)的可能性,而且也已經(jīng)出現(xiàn)可用插件。本文探討基leaflet為WEBGIS框架,實(shí)現(xiàn)多邊形切割插件。
1 切割思路及其算法
1.1 構(gòu)造初始切割對(duì)象
參照l(shuí)eaflet官方自帶的插件,采用面向?qū)ο蟮乃季S來(lái)構(gòu)建切割類CutPolygon。CutPolygon繼承于leaflet的核心類Hander,代碼如下:
var CutPolygon=L.Handler.extend({
includes: L.Mixin.Events,
options: {},
initialize: function (map, options) {
L.Handler.prototype.initialize.call(this, map);
L.setOptions(this, options);
this._map=map;
this._layerGroup=new L.FeatureGroup();
this._map.addLayer(this._layerGroup);
},
在CutPolygon中首先includes使切割對(duì)象賦予事件委托的方法。然后再CutPolygon的初始化方法中完成以下幾步:
⑴ 首先執(zhí)行hander的初始化方法;
⑵ 傳入map地圖對(duì)象以及其他屬性;
⑶ Cutpolygon的_map屬性對(duì)象指向map參數(shù);
⑷ 聲明一個(gè)圖層_layerGroup并添加進(jìn)map去;
1.2 鼠標(biāo)捕捉
該插件初始化使用時(shí)提供鼠標(biāo)捕捉多邊形上的點(diǎn)。多邊形的本質(zhì)為由大于等于一條線段所組成的線段首位銜接的不閉合的折線。(注:首尾銜接的不閉合為多邊形,直線為折線的特殊情況)。所以求解點(diǎn)到多邊形的距離的問(wèn)題就轉(zhuǎn)化為求解點(diǎn)到每個(gè)線段的距離。求解思路如下。
如圖1、圖2所示。標(biāo)注:線段l;偏離距離H;匹配的結(jié)果坐標(biāo)點(diǎn)P0;鼠標(biāo)點(diǎn)p及p到l的距離h;線段兩個(gè)端點(diǎn)A1、A2;線段所在直線l1;過(guò)線段兩端點(diǎn)做線段的法線p1、p2;P1、p2與線段所成內(nèi)夾角分別為a,b;P到A1和A2的距離分別為d1,d2;
以上是針對(duì)單條線段進(jìn)行的判斷,在一個(gè)多邊形中有n條線段,則對(duì)n條線段按照以上計(jì)算方式得到共n個(gè)捕捉匹配點(diǎn),對(duì)集合Zn求出最小值Hmin作為當(dāng)前位置p相對(duì)多邊形的捕捉點(diǎn)。
1.3 切割算法
多邊形按簡(jiǎn)易程度又可分為凹多邊形、凸多邊形以及帶島狀內(nèi)環(huán)的多邊形。由于凸多邊形可以看作是凹多邊形的特例,所以本文以凹多邊形為代表的任意多邊形來(lái)實(shí)現(xiàn)切割算法,針對(duì)帶島狀內(nèi)環(huán)的多邊形我們進(jìn)行搭橋無(wú)島化處理生成新的凹多邊形來(lái)進(jìn)行切割[1-2](無(wú)島化將在另外一篇文章講解)。
1.3.1 存儲(chǔ)構(gòu)造函數(shù)
為了數(shù)據(jù)便于管理,代碼開(kāi)始先定義一個(gè)構(gòu)造函數(shù)用于存儲(chǔ)交點(diǎn)以及多邊形頂點(diǎn)。該構(gòu)造函數(shù)參數(shù)為:距離,維度,經(jīng)度,在多變行所在的索引,多邊形。具體的代碼參考如下(注:當(dāng)不要距離參數(shù)時(shí)可默認(rèn)設(shè)置為0):
1.3.2 切割步驟
先構(gòu)建實(shí)例多邊形P,由點(diǎn)P0,P1,…,P10組成。顯而易見(jiàn),多邊形P是一個(gè)標(biāo)準(zhǔn)的凹多邊形,切割算法將以多邊形P為例進(jìn)行說(shuō)明,如圖3所示。
通過(guò)鼠標(biāo)雙擊拾取多邊形上一點(diǎn)a0,并將該多邊形存儲(chǔ)為FOCUSON焦點(diǎn)多邊形數(shù)據(jù)集中(注:若鼠標(biāo)處于某一個(gè)多邊形內(nèi)該多邊形自動(dòng)存儲(chǔ)為FOCUSON焦點(diǎn)多邊形數(shù)據(jù)集中,若在多邊形外則把_layerGroup圖層中所有的多邊形都加入FOCUSON焦點(diǎn)多邊形數(shù)據(jù)集中,鼠標(biāo)對(duì)所有多邊形計(jì)算距離,取最近點(diǎn)為拾取點(diǎn),切割線第一點(diǎn)確定后自動(dòng)將點(diǎn)所在多邊形確定為FOCUSON數(shù)據(jù)集中惟一的多邊形)。
鼠標(biāo)自動(dòng)在FOCUSON的多邊形上拾取第二點(diǎn)a5(注:需判斷a5在多邊形P中的索引是否等于a0的索引,防止處于同邊的情況),拾取的點(diǎn)與第一點(diǎn)構(gòu)建一條線段Polyline,隨著鼠標(biāo)移動(dòng),Polyline也動(dòng)態(tài)地改變。具體按照以下步驟。
⑴ 首先判斷交點(diǎn)數(shù)是否大于2,若等于2則計(jì)算以兩個(gè)交點(diǎn)作為端點(diǎn)的線段的中點(diǎn),計(jì)算此中點(diǎn)是否處于多邊形P內(nèi),處于執(zhí)行⑵,反之結(jié)束,多邊形P沒(méi)有切割,切割無(wú)效[3]。
⑵ 將a與多邊形P相交的交點(diǎn)按照交點(diǎn)所在線段的索引排序,按照上圖排序?yàn)閇4]。
⑶ 按照⑵的索引排序,以切割線端點(diǎn)為節(jié)點(diǎn)將⑵結(jié)果分成兩部分(a0→a5;a5→a0)。
⑷ 設(shè)a0與a5交點(diǎn)所在多邊形P邊的索引分別為Index0和Index5,針對(duì)線段a與多邊形P切割的結(jié)果可分為以下兩種情況[5]:
情況一:若⑵的結(jié)果a0→a5是相臨兩點(diǎn)沒(méi)有中間交點(diǎn),那么在多邊形P的坐標(biāo)點(diǎn)P0,P1,…,P10中,尋找處于(Index0+1,Index5)范圍內(nèi)所有的點(diǎn),如圖3所示可得
⑴
ZN中的坐標(biāo)點(diǎn)滿足要求,按照索引順序判斷a5→a0之間兩兩相臨交點(diǎn)的中心點(diǎn)是否處于多邊形P內(nèi),若結(jié)果為正確的話則不取處于相臨兩交點(diǎn)之間的多邊形頂點(diǎn),反之取多邊形的頂點(diǎn),并按照索引順序保存。如圖3所示,a5→a0方向判斷的結(jié)果為:
⑵
最后將⑴的Wn拼接于⑵的Zn的尾部形成:
⑶
式⑶中的Points首尾閉合形成的多邊形就是切割后的結(jié)果之一。
情況二:若⑵的結(jié)果a5→a0方向的有多個(gè)交點(diǎn)。按照索引順序判斷a5→a0之間兩兩相臨交點(diǎn)的中心點(diǎn)是否處于多邊形P內(nèi),若結(jié)果為否的話則按照索引順序保存相臨兩交點(diǎn)及處于兩交點(diǎn)之間的多邊形的頂點(diǎn),保存坐標(biāo)將構(gòu)成切割多邊形的結(jié)果之一,反之不做處理。循環(huán)遍歷每相臨兩點(diǎn)處理得到結(jié)果保存如上圖所示處理結(jié)果為:
⑷
情況一和情況二都需要注意一種特殊情況,當(dāng)多邊形的起點(diǎn)P0處于某一個(gè)切割多邊形內(nèi)時(shí)即P0處于處于兩個(gè)交點(diǎn)之間區(qū)域時(shí),點(diǎn)的索引排序則需要單獨(dú)處理。
1.3.3 多邊形切割流程圖
CutPolygon對(duì)象只提供對(duì)外調(diào)用接口,使用者并不需要了解內(nèi)部如何處理。在此簡(jiǎn)單梳理使用時(shí)的內(nèi)部流程圖。在聲明CutPolygon對(duì)象后,先進(jìn)行添加需要切割的多邊形,然后初始化屬性參數(shù),CutPolygon對(duì)象內(nèi)部初始化事件,然后通過(guò)鼠標(biāo)移動(dòng)事件mousemove和鼠標(biāo)雙擊事件dblclick來(lái)完成切割。CutPolygon內(nèi)部還提供自身調(diào)用的私有函數(shù),如:判斷點(diǎn)是否在多邊形內(nèi),WGS84坐標(biāo)轉(zhuǎn)Web墨卡托坐標(biāo),根據(jù)索引排序,刪除圖層所有要素,切割完刪除被切割的多邊形,CutPolygon數(shù)據(jù)更新,事件的注冊(cè)和注銷以及更新等[6]。以下為簡(jiǎn)化的流程圖。
2 實(shí)現(xiàn)效果
2.1 調(diào)用參考
在了解原理之后該如何調(diào)用寫(xiě)好的基于leaflet的開(kāi)發(fā)的多邊形切割的插件呢?在前端代碼中,調(diào)用leaflet并聲明map之后。新建CutPolygon對(duì)象,在構(gòu)件需要切割的多邊形的時(shí)候?qū)隒utPolygon對(duì)象中,然后初始化一下事件,即可調(diào)用。本文參照官方插件模式,也通過(guò)enbale開(kāi)啟切割,通過(guò)disable/ESC來(lái)關(guān)閉切割功能。以下為部分調(diào)用代碼:
3 結(jié)論
經(jīng)過(guò)以上方法設(shè)計(jì)出來(lái)的功能,在某公司研發(fā)的國(guó)土調(diào)查宗地管理系統(tǒng)得到應(yīng)用,基本滿足需求。在未來(lái)的發(fā)展中,這些基本功能需求是遠(yuǎn)遠(yuǎn)不夠的,而且緩沖區(qū),空間要素的拓?fù)潢P(guān)系判斷等等也需不斷適應(yīng)新需求。針對(duì)本文而言,該方法切割還缺少針對(duì)大量空間要素的一次性裁剪,這樣可以實(shí)現(xiàn)批量裁剪,節(jié)省大量時(shí)間以及多要素裁剪的同步性。這些問(wèn)題在后期需要繼續(xù)完善。
參考文獻(xiàn)(References):
[1] 吳信才.地理信息系統(tǒng)原理與方法[M].電子工業(yè)出版社,
2002.
[2] 周培德.計(jì)算幾何[M].清華大學(xué)出版社,2000.
[3] 陳瑞卿,周健,虞烈.一種判斷點(diǎn)與多邊形關(guān)系的快速算法[J].
西安交通大學(xué)學(xué)報(bào),2007.41(1):59-63
[4] 劉強(qiáng),陳玉健.論兩條直線段的求交[J].計(jì)算機(jī)學(xué)報(bào),1997.20
(12):1119-1123
[5] 田光,謝忠,吳亮.基于簡(jiǎn)單要素模型的多邊形分割算法[J].地
理與地理信息科學(xué),2010.26(1):24-28
[6] 孫小淋.基于JavaScript的消息管理機(jī)制探討[J].軟件,
2013.7.