OpenMap教程4 –图层
1.簡介
在第一個教程中,我們創建了一個基本的OpenMap GIS應用程序,該應用程序在JFrame中顯示一個從文件系統加載的具有一個形狀圖層的地圖。 該教程基于com.bbn.openmap.app.example.SimpleMap 。 在第二篇教程中,我們擴展了基本應用程序以使用MapHandler ,在第三篇教程中,我們了解了它如何利用openmap.properties將所有內容連接在一起。 在本教程中,我們將討論地圖圖層。
2.地圖圖層概述
在教程1中,我們看到了如何將ShapeLayer添加到MapBean 。 OpenMap支持大量的圖層類型,可以將它們添加到MapBean中, 如圖1所示。
BufferedLayerMapBean是使用BufferedLayer (請參見圖1 )為某些圖層創建圖像的MapBean 。 它使用“ Layer背景標志來確定應將哪些圖層添加到此緩沖的圖像。 任何不響應MouseEvent的層都應指定為背景層,以減少其paint()方法對應用程序的處理負擔。
OMGraphicHandlerLayer是基礎層類,實現了需要交互和共享OMGraphic的層的最常見功能。 GraticuleLayer在內部創建其OMGraphic ,而ShapeLayer從文件讀取數據。 DTEDLayer和RpfLayer具有圖像緩存。 有一些特殊的層允許您訪問空間數據庫以創建OMGraphic 。 可以在層內使用任何管理圖形的技術。
作為基類, OMGraphicHandlerLayer具有內置功能,可以更輕松地管理OMGraphic中的OMGraphic 。 擴展OMGraphicHandlerLayer ,請實現prepare()方法以返回OMGraphicList ,該OMGraphic包含適用于當前在圖層中設置的投影的OMGraphic 。 收集,準備和生成OMGraphic的所有工作都應在prepare()方法中執行。 OMGraphicHandlerLayer還具有內置的SwingWorker對象,可用于在單獨的線程中調用prepare() 。 可以通過調用doPrepare()方法來啟動SwingWorker線程。 如果在調用doPrepare()方法時SwingWorker已經很忙,則在原始線程完成時將啟動一個新線程來調用prepare() 。 在prepare()方法的默認實現中,當前列表只是使用當前投影生成并返回。
圖1:OpenMap的圖層類層次結構
有關如何使用這些層的更多信息,請參考開發者指南。
OpenMap還提供了一些培訓層( com.bbn.openmap.layer.learn ):
- 基本層
 - 互動層
 - SimpleAnimationLayer
 - 投影響應層
 
以及測試圖層( com.bbn.openmap.layer.test ):
- BoundsTestLayer
 - GeoCrossDemoLayer
 - GeoIntersectionLayer
 - GeoTestLayer
 - HelloWorldLayer
 - 測試層
 
最后, com.bbn.openmap.layer.DemoLayer是一個圖層如何使用OMDrawingTool編輯OMGraphic 。 它使用繪圖工具在地圖上創建區域,這些區域也用作過濾器,以控制哪些OMGraphic也是可見的。
層派生自java.awt.Component ,它們是可以添加到MapBean的唯一組件。 因為Layer s為Component小號包含一個內MapBean容器,的呈現Layer小號到地圖上由Java組件呈現機制控制。 該機制控制分層組件如何在彼此之上繪制。 為了確保按照正確的順序將每個組件繪制到窗口中, Component類包括一個方法,該方法允許其告知渲染機制它想被繪制。 此功能允許Layers彼此獨立工作,并讓MapBean避免知道Layer上正在發生什么。
OpenMap應用程序中的圖層可以使用來自許多來源的數據:
- 通過計算
 - 從本地硬盤驅動器的數據文件
 - 來自URL的數據文件
 - 從jar文件中包含的數據文件
 - 使用從數據庫(JDBC)檢索的信息
 - 使用從地圖服務器接收的信息(圖像或地圖對象)
 
2.1創建圖層
讓我們從最簡單的層開始。 從教程1開始,我們已經看到了如何創建ShapeLayer并將其添加到MapBean 。 但是,自從教程3開始,我們就具備了openmap.properties和MapHandler 。 這是您需要做的更改。
清單1 – openmap.properties
... # These layers are turned on when the map is first started. Order # does not matter here... openmap.startUpLayers=basic graticule shapePolitical # Layers listed here appear on the Map in the order of their names. openmap.layers=basic graticule shapePolitical# Basic Layer basic.class=com.bbn.openmap.layer.learn.BasicLayer basic.prettyName=Basic ...簡短提醒openmap.layers , openmap.layers引用要加載的圖層, openmap.startUpLayers引用在啟動時需要加載的圖層。 您會注意到已經添加了basic層。
結果可以在圖2中看到。從BasicLayer的JavaDoc中我們了解到,它擴展了OMGraphicHandlerLayer ,它包含很多功能,但是僅公開了在地圖上開始添加OMGraphic ( OMGraphic )所需的方法。 這是一個對象永不更改的層,該層使用的地圖對象也永不更改。 即使它們不在可見的地圖上,也始終可以對其進行管理和繪制。 當投影改變時, OMGraphic被告知新的投影是什么,以便它們可以重新定位自己,然后重新繪制它們。 如果您想了解更多關于與OMGraphic進行交互的OMGraphic ,可以有效地顯示它們,然后移至InteractionLayer 。
層實現ProjectionListener接口以偵聽ProjectionEvent 。 當投影改變時,他們可能需要重新獲取,重新生成其圖形,然后將自己重新繪制為新視圖。 我們將在以后的教程中談論有關投影的更多內容。
BasicLayer將覆蓋從兩種方法OMGraphicHandlerLayer :
- prepare() :當將圖層添加到地圖或地圖投影更改時,將調用此方法。 我們需要確保從此方法返回的OMGraphicList是我們想要繪制在地圖上的內容。 OMGraphic需要使用當前投影生成。 我們在層中測試OMGraphicList是否為空,以查看是否需要創建OMGraphic 。 該層不會針對不同的投影更改其OMGraphic ,如果您的圖層做了更改,則需要清除OMGraphicList并添加當前投影所需的OMGraphics 。
 - init() :如果層發現其OMGraphicList為null , OMGraphicList prepare()方法調用。
 
圖2:基本層
清單2 – prepare()方法
public synchronized OMGraphicList prepare() {OMGraphicList list = getList();if (list == null) {list = init();}list.generate(getProjection());return list;}getList()返回上次調用prepare()時從此方法返回的內容。 在此示例中,我們始終返回OMGraphicList對象,因此,如果它為null ,則必須尚未調用prepare() 。 在這種情況下,將調用init() 。
在返回地圖對象列表之前,設置圖層投影的調用至關重要! 需要告訴OMGraphic自己在哪里繪畫,他們會在generate(Projection)調用中為他們提供當前Projection時弄清楚。 如果OMGraphic的位置發生了變化,則在呈現它之前需要重新生成它,否則它不會自己繪制。 當OMGraphic的投影更改(縮放和平移)出現但在OMGraphic更改后的任何其他時間都沒有出現時,您可能會產生問題。 如果您想提高效率,可以將對列表的調用替換為上面(list == null)檢查的else子句,并在下面的init()方法中對所有OMGraphics調用generate(Projection)創建它們。 這將防止OMGraphicList.generate(Projection)調用在返回所有OMGraphic之前對其進行OMGraphic 。
清單3 – init()方法
public OMGraphicList init() {OMGraphicList omList = new OMGraphicList();// Add an OMLineOMLine line = new OMLine(40f, -145f, 42f, -70f, OMGraphic.LINETYPE_GREATCIRCLE);// line.addArrowHead(true);line.setStroke(new BasicStroke(2));line.setLinePaint(Color.red);line.putAttribute(OMGraphicConstants.LABEL, new OMTextLabeler("Line Label"));omList.add(line);// Add a list of OMPoints.OMGraphicList pointList = new OMGraphicList();for (int i = 0; i < 100; i++) {OMPoint point = new OMPoint((float) (Math.random() * 89f), (float) (Math.random() * -179f), 3);point.setFillPaint(Color.yellow);point.setOval(true);pointList.add(point);}omList.add(pointList);return omList; }當prepare()返回null時,將調用init()方法。 它創建要添加到圖層的OMGraphic ( OMGraphic )。
作為一個簡短的教程,一個典型的GIS應用由圖(的MapBean在OpenMap),其由層(的Layer即由特征(對象) OMGraphic S)。 下圖顯示了OMGraphic的類層次結構。
圖3:OMGraphics類層次結構
清單3的代碼創建了一個OMLine和100個OMPoint 。 OMGraphic是柵格和矢量圖形對象,它們知道如何在給定的xy窗口或經緯度地圖投影上定位和渲染自己。 您所要做的就是提供位置數據(x / y,緯度/經度)和圖形信息(顏色,線寬),然后圖形處理其余部分。
這應該是一個簡單而良好的開始(在下面的教程中,我們將看到例如如何顯示數據庫中的數據),但是您可能已經注意到,沒有交互性。 交互性由InteractionLayer演示。 您現在應該可以在openmap.properties中用InteractionLayer替換Basic層。
InteractionLayer演示了如何與地圖上的OMGraphic進行交互,使它們可以通過鼠標事件更改外觀并提供有關自身的其他信息。 該層基于BasicLayer演示的BasicLayer 。
圖4:交互層
如果運行該應用程序,則會注意到將鼠標移到OMPoint上時,它會改變顏色。 您也可以右鍵單擊它以顯示彈出菜單。 我們將使用此功能來顯示功能的屬性。 您可以自己查看com.bbn.openmap.layer.learn.InteractionLayer 。 我只是在這里簡單介紹了一些有關如何向OMGraphicHandlerLayer添加交互的OMGraphicHandlerLayer 。 不要忘記在構造函數中添加以下行:
清單4 – setMouseModeIDsForEvents()
// Making the setting so this layer receives events from the // SelectMouseMode, which has a modeID of "Gestures". Other // IDs can be added as needed. You need to tell the layer which // MouseMode it should listen to, so it can tell the MouseModes to send // events to it. // Instead of "Gestures", you can also use SelectMouseMode.modeID or // OMMouseMode.modeID setMouseModeIDsForEvents(new String[] { SelectMouseMode.modeID }); // "Gestures"這實際上告訴您的圖層,其功能應響應鼠標手勢(例如,鼠標懸停)。 可以由某些OpenMap組件管理MouseEvent ,將它們定向到圖層和OMGraphic 。 MouseMode描述如何解釋和使用MouseEvent和MouseMotionEvent 。 該MouseDelegator是真正MouseListener和MouseMotionListener在MapBean 。 MouseDelegator管理MouseMode的列表,并知道在任何給定時間哪個是“活動的”。 MouseDelegator還向活動圖層詢問其MapMouseListener ,并將對活動MouseMode中的事件感興趣的圖層作為偵聽器添加到該模式。
當從MapBean觸發MouseEvent時,它將通過MouseDelegator進入活動的MouseMode ,在此MouseMode開始向其MapMouseListener提供MouseEvent 。 每個偵聽器都有機會使用該事件。 MapMouseListener可以自由地對事件進行操作而不使用事件,因此它可以繼續傳遞給其他偵聽器。
MapMouseListener提供了一個有興趣從中接收事件的所有MouseMode ID字符串的String數組,并且還具有MouseEvent和MouseMotionEvent到達的自己的方法MapMouseListener可以將這些事件與OMGraphicList結合使用來查找如果事件發生在任何OMGraphic ,請發出OMGraphic ,并在必要時進行響應。
您的圖層可以與許多MouseModes進行交互。 在源代碼中或在此處搜索modeID返回以下8種鼠標模式(重復兩次):
- DistanceMouseMode.modeID = "Distance"
 - DistQuickToolMouseMode.modeID = "Distance"
 - NavMouseMode.modeID = "Navigation"
 - NullMouseMode.modeID = "None"
 - OMDrawingToolMouseMode.modeID = "Drawing"
 - OMMouseMode.modeID = "Gestures"
 - PanMouseMode.modeID = "Pan"
 - RangeRighsMouseMode.modeID = "RangeRings"
 - SelectMouseMode.modeID = "Gestures"
 - ZoomMouseMode.modeID = "Zoom"
 
創建功能時,請不要忘記在功能上添加如下所示的內容,以便在鼠標懸停在功能上時進行視覺顯示: point.setSelectPaint(Color.yellow);
您可以重寫以下方法:
- isSelectable() –查詢OMGraphic是否可選。 您必須返回true才能使其可選。
 - isHighlightable() –查詢當鼠標移到OMGraphic上時可以突出顯示它。
 - getInfoText() –當鼠標懸停在OMGraphic時在狀態欄中顯示文本
 - getToolTipTextFor() –當鼠標懸停在OMGraphic時顯示工具提示
 
例如
清單5 –交互方法
/*** Query that an OMGraphic can be highlighted when the mouse moves over it.* If the answer is true, then highlight with this OMGraphics will be* called, and unhighlight will be called with the mouse is moved off of it.* * @see com.bbn.openmap.layer.OMGraphicHandlerLayer#highlight* @see com.bbn.openmap.layer.OMGraphicHandlerLayer#unhighlight*/public boolean isHighlightable(OMGraphic omg) {return true;}/*** Query that an OMGraphic is selectable. Examples of handing selection are* in the EditingLayer. The default OMGraphicHandlerLayer behavior is to add* the OMGraphic to an OMGraphicList called selectedList. If you aren't* going to be doing anything in particular with the selection, then return* false here to reduce the workload of the layer.* * @see com.bbn.openmap.layer.OMGraphicHandlerLayer#select* @see com.bbn.openmap.layer.OMGraphicHandlerLayer#deselect*/public boolean isSelectable(OMGraphic omg) {return true;}如果要在右鍵單擊OMGraphic時顯示彈出菜單,請覆蓋以下方法以返回菜單項列表。 在以后的教程中,我們將使用此方法顯示數據庫中要素的屬性。
- List getItemsForOMGraphicMenu(OMGraphic omg)
 
如果要在右鍵單擊圖層上的任何位置時顯示彈出菜單,請重寫以下方法以返回菜單項列表:
- List getItemsForMapMenu(MapMouseEvent me)
 
我希望這很好,并不困難,但是您不能隨意移動功能。 例如,我希望能夠選擇OMPoint并將其拖動到新位置。 為了能夠添加此功能,我們需要研究以上列表中未列出的一些層:
- com.bbn.openmap.layer.DemoLayer
 - com.bbn.openmap.layer.DrawingToolLayer
 - com.bbn.openmap.layer.editor.EditorLayer
 
嘗試其中的每一個。 在上一教程中,我們實際上已經看到了DemoLayer ,但是我們沒有研究代碼。 因此,為了能夠拖動/修改功能,您需要:
- 實現DrawingToolRequestor接口
 - 在findAndInit()定義并初始化DrawingTool的實例
 - 相應地修改isSelectable() , getInfoText() , getToolTipTextFor()
 - 覆蓋select()和drawingComplete()方法,如清單4所示。
 
清單6 –如何在地圖上繪制
public class DemoLayer extends OMGraphicHandlerLayer implements DrawingToolRequestor {protected DrawingTool drawingTool; ...public DrawingTool getDrawingTool() {// Usually set in the findAndInit() method.return drawingTool;}public void setDrawingTool(DrawingTool dt) {// Called by the findAndInit method.drawingTool = dt;}@Override public void findAndInit(Object someObj) {if (someObj instanceof DrawingTool) {setDrawingTool((DrawingTool) someObj);}}@Overridepublic void findAndUndo(Object someObj) {if (someObj instanceof DrawingTool) {if (getDrawingTool() == (DrawingTool) someObj) {setDrawingTool(null);}}}@Overridepublic boolean isSelectable(OMGraphic omg) {DrawingTool dt = getDrawingTool();return (dt != null && dt.canEdit(omg.getClass()));}@Overridepublic String getInfoText(OMGraphic omg) {DrawingTool dt = getDrawingTool();return (dt != null && dt.canEdit(omg.getClass())) ? "Click to edit graphic." : null;}@Overridepublic String getToolTipTextFor(OMGraphic omg) {Object tt = omg.getAttribute(OMGraphic.TOOLTIP);if (tt instanceof String) {return (String) tt;}String classname = omg.getClass().getName();int lio = classname.lastIndexOf('.');if (lio != -1) {classname = classname.substring(lio + 1);}return "Your Layer Object: " + classname;}@Overridepublic void select(OMGraphicList list) {if (list != null && !list.isEmpty()) {OMGraphic omg = list.getOMGraphicAt(0);DrawingTool dt = getDrawingTool();if (dt != null && dt.canEdit(omg.getClass())) {dt.setBehaviorMask(OMDrawingTool.QUICK_CHANGE_BEHAVIOR_MASK);if (dt.edit(omg, this) == null) {// Shouldn't see this because we checked, but ...fireRequestInfoLine("Can't figure out how to modify this object.");}}}}@Overridepublic void drawingComplete(OMGraphic omg, OMAction action) {if (!doAction(omg, action)) {// null OMGraphicList on failure, should only occur if// OMGraphic is added to layer before it's ever been// on the map.setList(new OMGraphicList());doAction(omg, action);}repaint();}... }現在,當您運行該應用程序時,便可以選擇一個特征并將其拖動到新位置,或修改其幾何形狀(用于直線,圓等)。
單擊“ Drawing Tool Launcher按鈕時,您可以在圖層上添加許多類型的圖形,而這可能不是您想要的。 例如,您可能希望您的圖層僅顯示OMPoint并且您不希望用戶能夠使用“ Drawing Tool向其添加例如線或圓。 如果您修改openmap.components以僅omdrawingtool和ompointloader (或僅保留應用程序中使用的OM加載程序的類型),則可以輕松完成此操作:
清單7 –不顯示繪圖工具的openmap.components(omdt)
openmap.components=menulist informationDelegator projFactory projectionstack toolBar zoompanel navpanel scalepanel projectionstacktool addlayer layersPanel overviewMapHandler layerHandler mouseDelegator projkeys coordFormatterHandler mouseModePanel mouseMode selectMouseMode navMouseMode distanceMouseMode panMouseMode omdrawingtool ompointloader另一個問題是,當右鍵單擊OMPoint ,將顯示與通過getItemsForOMGraphicMenu()創建的彈出菜單不同的彈出菜單。
罪魁禍首是OMDrawingTool 。 由于OpenMap是一個開源項目,因此建議您閱讀上述類的代碼( com.bbn.openmap.tools.drawing.OMDrawingTool )。 實際上,在方法select()您將看到以下行:
dt.setBehaviorMask(OMDrawingTool.QUICK_CHANGE_BEHAVIOR_MASK);OMDrawingTool定義了許多行為掩碼:
- SHOW_GUI_BEHAVIOR_MASK
 - GUI_VIA_POPUP_BEHAVIOR_MASK
 - USE_POPUP_BEHAVIOR_MASK
 - ALT_POPUP_BEHAVIOR_MASK
 - PASSIVE_MOUSE_EVENT_BEHAVIOR_MASK
 - DEACTIVATE_ASAP_BEHAVIOR_MASK
 - DEFAULT_BEHAVIOR_MASK
 - QUICK_CHANGE_BEHAVIOR_MASK
 
您可以嘗試所有這些方法以查看圖層的行為。 不幸的是,它們都不能滿足我們的需求。 如果沒有彈出窗口(或我們的彈出窗口)出現,則該功能無法拖動到其他位置; 如果出現彈出窗口, OMDrawingTool 。 所以,去黑客。 我們將創建自己的OMDrawingTool :
清單8 – MyDrawingTool類
public class MyDrawingTool extends OMDrawingTool {public MyDrawingTool() {super();setBehaviorMask(OMDrawingTool.QUICK_CHANGE_BEHAVIOR_MASK);}@Overridepublic JPopupMenu createPopupMenu() {JPopupMenu popup = super.createPopupMenu(); popup.removeAll();popup.add(new JMenuItem("Which"));popup.add(new JMenuItem("Why"));return popup;} }您甚至可以進一步添加set方法來設置由getItemsForOMGraphicMenu()方法創建的JMenuItem列表,但是我將其作為練習留給您。 我們需要再做一件事:
清單9 –顯示我們的繪圖工具的openmap.properties
omdrawingtool.class=openmap.MyDrawingTool #omdrawingtool.class=com.bbn.openmap.tools.drawing.OMDrawingTool通過此更改,您可以刪除在圖層的select()方法中設置行為掩碼的行。
OpenMap圖層也支持動畫。 用openmap.properties SimpleAnimationLayer替換上一層。 當您再次重新運行該應用程序時,您會看到一個空的地圖。 單擊圖層按鈕,然后選擇AnimationLayer的屬性(請參見圖5 )。 在出現的對話框中,通過單擊相應的按鈕添加精靈,一旦滿意,請選中“ 運行計時器”復選框以查看它們的移動。 您可以調整“計時器間隔”滑塊以查看它們移動得更快或更慢。
圖5:動畫層
前面提到的所有層都擴展了OMGraphicHandlerLayer 。 但是您可以沒有它。 例如,看一下HelloWorldLayer ,它直接覆蓋Layer 。 它的createGraphics()方法創建功能并將其添加到傳遞的OMGraphicList 。
鼓勵您檢查本文開頭提到的其他層,例如TestLayer , GeoTestLayer等。
要在“圖層”對話框中啟用“ 屬性”按鈕并能夠顯示某些內容,您需要重寫getGUI()方法。 參見例如TestLayer或SimpleAnimationLayer 。
3.結論
本教程專門介紹OpenMap的圖層。 我們從簡單的BasicLayer (顯示靜態數據)開始,然后添加了與InteractionLayer ,演示了如何使用鼠標將要素移動到新的地圖位置或修改要素的幾何形狀,并繼續使用AnimationLayer演示了如何為圖層的要素設置動畫。 我們沒有涵蓋所有內容。 即使看到了如何添加和操作功能,我們仍然沒有討論投影。 在下一個教程中,我們將構建第一個三層應用程序,在該應用程序中,我們將看到如何在地圖上顯示數據庫中的數據。
翻譯自: https://www.javacodegeeks.com/2016/01/openmap-tutorial-4-layers.html
總結
以上是生活随笔為你收集整理的OpenMap教程4 –图层的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: Linux for 循环(linux f
 - 下一篇: 宿州房产网上备案查询房(宿州房产网上备案