高自強
(河北省地勘局測繪院,河北廊坊 065000)
基于MapInfo的線對象剪斷功能探討*
高自強
(河北省地勘局測繪院,河北廊坊 065000)
將MapInfo軟件的線剪斷功能和MapGIS軟件的線剪斷功能進行比較,指出MapInfo的線剪斷功能單一的問題。為此,介紹了一種利用MapBasic編譯生成線對象剪斷工具的方法,較好地解決了這一問題。
MapGIS;MapInfo;線對象;剪斷功能
MapInfo提供了一些點線面及注記工具,能進行圖形對象的基本編輯操作。然而,在地質(zhì)測繪行業(yè)中,大多數(shù)電子地圖數(shù)據(jù)生產(chǎn)的從業(yè)人員由于用慣了其他圖形編輯軟件,總感覺MapInfo的圖形操作工具過于單調(diào)。例如,熟悉MapGIS的人就對Map-Info的線剪斷功能心存芥蒂。為此,筆者設(shè)計了一種MapInfo環(huán)境下的線剪斷模型,較好地解決了這一問題。
在MapGIS中,軟件為用戶提供了多種剪斷線工具,主要有:“線編輯”菜單下的“剪斷線”功能(高版本MapGIS提供3種方式:有剪斷點、無剪斷點和定比剪斷);“線編輯”菜單下的“相交線剪斷”功能(2種方式:剪斷母線和不剪斷母線);“其他”菜單下的“自動剪斷線”——對全圖作完全線剪斷處理。這些方式幾乎窮盡了剪斷線的所有方式,使用也相當方便。
MapInfo軟件也為用戶提供了剪斷線的功能,一般做法是:
1)首先置當前表為“可編輯”,選中要剪斷的線。
2)點擊“對象/設(shè)置目標”菜單,將選中的線對象設(shè)置為當前目標。
3)選中另一個線對象,此線對象應(yīng)滿足兩點:一是必須與目標對象相交,二是兩對象之交點就是準備剪斷的位置。如果沒有這樣的線對象存在,則需要利用輸入折線工具增加一個。
4)點擊“對象/折線分割”菜單,完成目標對象的切割。
5)如果切割器是臨時生成的,最后還要將其刪除。
很顯然,與MapGIS相比,MapInfo中的剪斷線功能單一、操作繁瑣。
MapInfo提供一種名為MapBasic開發(fā)工具,它是一種類似Basic的解釋性語言,語法規(guī)則和函數(shù)與通用Basic語言極其相似,有一定Basic基礎(chǔ)的人員能很快學會使用。利用MapBasic編譯生成的*.mbx文件能在MapInfo環(huán)境下直接運行,因而可以用MapBasic生成Mbx用以擴展MapInfo的功能。下面分析用MapBasic生成MapInfo環(huán)境下線剪斷工具的基本模型:
第一,該工具應(yīng)能作為菜單項或工具箱項于啟動MapInfo時即自動運行并駐留至MapInfo退出,以便隨時調(diào)用。
第二,使用時不進行更多的操作,只須選中該工具后在地圖窗口中單擊線對象需要剪斷的部位即可將原來的對象一分為二。
第三,被剪斷后形成的新對象保留原對象的樣式和屬性,而且其任何片斷均能保留原對象相應(yīng)片斷的走向(延伸方向)。
第四,不必進行任何其他操作就可以無限次地重復(fù)使用。
上述第一項和第四項,利用MapBasic提供的Alter Menu語句和Create ButtonPad語句就可實現(xiàn)。
利用MapBasic建立新的線對象的一般做法是:先用Create pline語句創(chuàng)建一個節(jié)點數(shù)為0的空對象,再依次向其增加節(jié)點,最后用Insert語句將這個新對象插入文件。為說明方便,把需要剪斷的原始線對象稱為L0,把剪斷后的兩個線對象稱為L1和L2,把單擊位置的坐標定義為(x,y)。L1應(yīng)包含L0從首節(jié)點開始的若干節(jié)點,其末節(jié)點就是(x,y);相應(yīng)的,L2以(x,y)為首節(jié)點,并且包含L0除L1已經(jīng)用到的節(jié)點之外的所有節(jié)點。
但是,存在問題是:雖然從地圖窗口中取得坐標是可以實現(xiàn)的,但這個坐標究竟位于L0的哪一個片斷中,L1(或L2)究竟包含L0的哪幾個節(jié)點。由于用MapInfo的選擇工具選擇一個對象并不要求單擊位置一定要位于對象之上,當單擊發(fā)生于對象附近一定范圍內(nèi)時,該對象就能被選中,因而僅以單擊位置作為(x,y)加入對象中,必然會有一定偏差,L1的最后一個片斷和L2的第一個片斷實際上已經(jīng)偏離了原來的走向。
如圖1所示,L0就是前述的原始線對象(圖中只畫了它的一部分),圓O的圓心就是鼠標單擊位置,其半徑為一個定長d,圓O與L0的一個片斷——線段AB交于M點和N點,直線OP為AB的垂線,P點為垂足。顯然,P點就是將L0分為L1和L2的分割點。
圖1 剪斷點的定位示意圖Fig.1 Positioning schematic of snipped point
求P點坐標的過程是:把圓O看作一個線對象Obj1,然后以A(x1,y1)和B(x2,y2)為節(jié)點構(gòu)造一個新的折線對象Obj2,用MapBasic提供的函數(shù)IntersectNodes可以返回一個線對象Obj3,代碼如下:
Obj3=IntersectNodes(Obj1,Obj2,INCL_ALL)
這個新對象包含兩個節(jié)點,其首節(jié)點為M,末節(jié)點為N,坐標分別為:
線段MN的中分點P的坐標公式為:
為了給前文提到的圓O的半徑d定義一個合理的值,筆者進行了一個實驗,實驗代碼如下:
執(zhí)行以上代碼需要建立一個名稱為“實驗”的MapInfo表文件,在該表中畫一條豎直的折線對象。將上述代碼復(fù)制粘貼至MapBasic文檔中,編譯后執(zhí)行,程序?qū)⒃贛apInfo中添加一個有ToolButton按鈕的工具箱,點擊該按鈕,在折線對象左側(cè)距離折線稍遠一點的位置單擊,此時MapInfo沒有任何反應(yīng),接著,慢慢向折線移動鼠標并單擊,當單擊點很接近折線時,屏幕右下方出現(xiàn)一個消息框,報告一個數(shù)字。繼續(xù)從折線左側(cè)趨近折線,不斷有數(shù)字報告。重復(fù)多次后,改為從折線右側(cè)趨近折線。結(jié)果如圖2所示。
圖2 實驗結(jié)果Fig.2 Experiment result
如果把那條豎直線改為水平線,把上面代碼中的print d/(x1-x)改為print d/(y1-y),結(jié)果基本相同。
上面代碼中“d=MapperInfo(i_win_id,MAPPER_INFO_SCALE)”將當前地圖窗口的顯示比例賦給變量d。這段代碼的執(zhí)行結(jié)果說明,當點擊位置與對象的距離約為窗口顯示比例分母的1/30或更近時,該對象即可被選中。
根據(jù)以上的分析和測試,當d取值不小于當前窗口顯示比例的1/30時,圓O就會與折線相交。為彌補測試誤差,把d的值定為窗口顯示比例的1/20。
代碼如下:
主過程Main向MapInfo界面中加入一個標題為“線工具”的工具箱,并向工具箱放入一個ToolButton按鈕,該功能由Create ButtonPad語句完成。MapBasic允許定義如下3種類型的按鈕:
第一種:ToolButton工具按鈕。當用戶單擊ToolButton工具按鈕時,它處于激活狀態(tài)直到選擇了另一個工具。當一個工具按鈕處于激活狀態(tài)時,如果用戶在某種MapInfo窗口單擊,將調(diào)用由Calling子句指定的處理程序。ToolButton的Icon子句指定按鈕的顯示圖案。MapBasic的安裝目錄下有一“SAMPLESMAPBASICICONDEMO”子目錄,雙擊其下的 ICONDEMO.MB文件,在打開的MapBasic窗口下編譯并執(zhí)行,它將為MapInfo添加一個Icon Sampler菜單項,依次選取其下的子菜單打開各種工具箱,單擊合適的按鈕出現(xiàn)對話框(見圖3)。把Constant項下的文本內(nèi)容復(fù)制粘貼到ToolButton的Icon子句中即可完成按鈕圖案的定義(直接在該子句中填入ID號也可以);ToolButton的Cursor子句定義該按鈕處于激活狀態(tài)時的鼠標形狀,Draw-Mode子句指定該按鈕在地圖窗口中的繪圖方式;Calling子句指定與按鈕對應(yīng)的子過程名,即按鈕的處理程序;HelpMsg子句指定提示文本的內(nèi)容,文本內(nèi)容前加“ ”的功能是,當鼠標在按鈕上停留時顯示提示文本。
圖3 Icon ID對話框Fig.3 Icon ID dialog box
第二種,PushButton觸發(fā)式按鈕。用戶鼠標左鍵點擊Push-Button觸發(fā)式按鈕時,與它連接的子過程立即被執(zhí)行。
第三種,ToggleButton開關(guān)式按鈕,當用戶單擊這類按鈕時,按鈕會在按下/非按下之間來回變換,同時程序會調(diào)用相應(yīng)子過程。
PushButton和ToggleButton都沒有Cursor和DrawMode子句。需要指出的是,為了能夠使用各種圖標,MapBasic程序必須包含如下代碼行(一般將其置于程序文件的開始部分):
Include"icons.def"
本文只給出實現(xiàn)線剪斷功能的一般過程:選擇線(獲取其所在表文件名、行號、屬性值)創(chuàng)建以d為半徑的圓折線對象通過循環(huán)將被選擇的線對象的各個片斷作為獨立線對象如果此對象與圓對象相交則計算它們的相交部分、依前述公式取得交點坐標、同 時記錄片斷位置創(chuàng)建一個與原對象樣式相同的折線對象并添加第一部分節(jié)點坐標將選擇的線對象的obj列Update 為此新對象再創(chuàng)建一個與原對象樣式相同的折線對象并添加第二部分節(jié)點坐標將此新對象插入原表將新對象的屬性Update為原屬性值。
由于MapInfo在許多函數(shù)和語句中并不支持以變量表示的表文件名,因此,如s_tab為一表名變量,用“Obj1=s_tab.obj”這樣的賦值語句并不能取得一個對象,程序會報錯。解決方法是,先聲明一個alias類型變量(例如oli),賦值如下:
oli=s_tab+ ”.obj”
Obj1=oli
則Obj1的值就是所要的對象。還應(yīng)注意,創(chuàng)建新的折線對象時,如果要求該對象與原對象的方向一致,應(yīng)反向賦值,即依次從末節(jié)點向首節(jié)點添加坐標。
仔細分析圖1可知,當單擊點剛好位于要剪斷的線的某個節(jié)點附近時,用上述方法取得的坐標反而發(fā)生了偏移。其實,只需添加一個條件語句就能解決這個問題,即當循環(huán)枚舉原線節(jié)點坐標時,如果發(fā)現(xiàn)單擊點與某節(jié)點的距離小于d時,則將該節(jié)點作為剪斷點。
在MapBasic界面下將代碼編譯為mbx文件后,雙擊即可執(zhí)行。如果要在啟動MapInfo時自動運行,則可將mbx文件拷貝至“C:Program FilesMapInfoProfessionalTools”,執(zhí)行MapInfo環(huán)境下的“工具/工具管理器”菜單命令,在圖4的界面中選“增加工具”,為工具指定標題和位置。確定后將新工具右側(cè)的自動裝入框選中即可。
圖4 工具管理器界面Fig.4 The interface of the manager of tools
[1]關(guān)健.MapInfo系統(tǒng)功能擴展幾例[J].城市勘測,2005(4):35~37.
[2]劉光.地理信息系統(tǒng)二次開發(fā)教程——語言篇[M].北京:清華大學出版社,2003.
Primarily Probing into the Snipping Function of Line Object Based on MapInfo
GAO Zi-qiang
(Hebei Institute of Geological Surveying and Mapping,Langfang Hebei 065000,China)
By comparison the line snipping function between MapInfo and MapGIS,this paper points out that the line snipping function of MapInfo is single,for this reason,the paper introduces one kind of method to apply MapBasic compiling and generating way of line object snipping tool,then well solving the problem.
MapGIS;MapInfo;line object;snipping function
P 208
B
1007-9394(2012)02-0038-03
2011-07-11
高自強(1963~),男,滿族,河北灤南人,碩士,高級工程師,現(xiàn)主要從事工程測量及GIS方面的工作。