隨筆-60  評論-138  文章-1  trackbacks-0

          前言: 
                如果您對JTS這三個詞還是沒有一個概念,那么推薦您關注一下sinoly的博客。這個我能夠找到為數不多的關于jts的中文資料。
                http://www.aygfsteel.com/sinoly/archive/2007/02/09/99042.html
               下面這段話就是摘抄自sinoly老兄的博客: 
                  ............它主要是完成了java對幾何對象、空間拓撲得核心操作算法。.......集成了java對幾何對象(點、線、面等)的對象管理外更大一部分工作是在完成對各種幾何對象的buffer、analyze以及空間索引.
                本文想要向您展示的就是一個空間索引的小小demo!
            
                 jts本身有一個包就叫Index,當中分別給出了SpatialIndex接口的幾個實現。本文展現的就是quadtree的用法。
                 quadtree翻譯過來就是四叉樹的意思,有一個很簡單的例子可以來理解四叉樹和空間索引的關系。那就是把中國的版圖來個十字型的分割,這樣就形成一個中心點和四個子節點。然后將每個子節點再次的進行十字分割。當分割到極小處時,整個中國的版圖就可以使用一個掛載很多節點的四叉樹來表示。每一個節點可以認為是一個具有經緯度及其描述信息的對象。
                 當我們手中有很多點的時候,想要建立成一顆四叉樹,只要把上邊的思路反過來就可以了(對于每個節點之間的距離是否相等,目前我還沒有好的認識)。
                 正如我們研發部local search的文斌而言,思路很簡單,但是不是每個人你都能夠實現。接下來,讓demo的代碼說話。

                1.建立一個對象,這個對象描述point除了經緯度外的其他信息(如果需要可以加上經緯度)。
               

           1/**
           2 * 
           3 * @author lang
           4 * @date 2007-12-17
           5 * @email lanfanss@126.com
           6 * @desc 代表point的信息
           7 * @since
           8 * 
           9 */

          10public class PointInfo {
          11    /**
          12     * 名稱
          13     */

          14    private String name;
          15    private String info;
          16
          17    public String getInfo() {
          18        return info;
          19    }

          20
          21    public void setInfo(String info) {
          22        this.info = info;
          23    }

          24
          25    public PointInfo(String name) {
          26        super();
          27        this.name = name;
          28    }

          29
          30    public String getName() {
          31        return name;
          32    }

          33
          34    public void setName(String name) {
          35        this.name = name;
          36    }

          37}

          2.接下來就是建立一顆樹,代碼如下
          public static void main(String[] args) {
                  Quadtree quatree 
          = new Quadtree();
                  
          // 構建幾個點
                  PointInfo info1 = new PointInfo("故宮");
                  quatree.insert(
          new Envelope(new Coordinate(116389373992178)), info1);
                  PointInfo info2 
          = new PointInfo("太和殿");
                  info2
                          .setInfo(
          "太和殿,俗稱金鑾殿,是宮殿群中最大的建筑。殿高36米,寬63米,面積為2380平方米。 “太和”語出《周易》,太和是“陰陽會和,沖和之氣也”,“混同宇內以玉太和”之意,即指宇宙萬物,和諧圓滿。太和殿坐落在“工”字形須彌座上,漢白玉雕成,分上中下三層,稱為丹墀或丹陛。雕欄稱為望柱,柱頭雕以云龍云圖案。那些伸出的為螭首,口中小孔為出水孔。共有螭首1142個。如遇雨天,可見千龍吐水之奇觀。 臺基上放置18個大銅爐,據說代表當時的18個省份。太和殿臺基上面的大平臺,放置銅龜、銅鶴各一對,象征“龜鶴千秋”,意為長壽。東有日晷西有喜量,象征皇權公正平允。這里是舉行大典奏九韶之樂的地方。");
                  quatree.insert(
          new Envelope(new Coordinate(116390733991605)), info2);
                  PointInfo info3 
          = new PointInfo("中和殿");
                  info3
                          .setInfo(
          " 中和殿在太和殿后,平面呈方形。“中和”語出《禮記.中庸》,指不偏不倚,凡事做到恰如其分。 殿為方形攢尖頂,在三大殿中居中,也最小,是皇帝去太和殿大典之前休息的地方。皇帝去天、地、日、月四壇祭祀時,前一天也要在中和殿里看祭文。每年二月皇帝到先農壇舉行親耕儀式,前一天要來這里閱視種子、農具、祝文。這里現陳列的是乾隆年間的兩頂肩輿,即八抬大轎。 ");
                  quatree.insert(
          new Envelope(new Coordinate(116390813991647)), info3);
                  PointInfo info4 
          = new PointInfo("保和殿");
                  info4
                          .setInfo(
          "保和殿,其意為“志不外馳,恬神守志”,就是說神志得專一,以保持宇內的和諧,才能福壽安樂,天下太平。 保和殿比太和殿規模小些,為重檐歇山頂。明朝冊立皇后,太子時,皇帝在此殿受賀。在清朝是舉行盛大宴會的地方。每年初一和十五在此宴請外族王公大臣,場面是十分壯觀的。公主下嫁時,也在這個殿里宴請附馬。這個殿最有名的事是舉行殿試。殿試就是皇帝本人親自監考、主考,是科舉考試的最高層次。前三名分別為狀元、榜眼、探花。 保和殿后是故宮最大的一塊雕石——云龍雕石,這塊苑葉青石長16.57米,寬3.07米,厚1.7米,總重二百多噸。上雕游龍,雙龍戲珠,游于云霧之中。 ");
                  quatree.insert(
          new Envelope(new Coordinate(116390793991698)), info4);
                  PointInfo info5 
          = new PointInfo("乾清宮");
                  info5
                          .setInfo(
          "乾清宮明朝時為皇帝居住之處,皇帝在此處理政務、召見臣仆和外國使節。從清朝雍正皇帝之后,皇帝遷到養心殿居住,但仍在此批閱奏報,召見大臣。 乾清宮除是皇帝的寢宮和日常自理政務外,還舉行元旦、燈節、端午、中秋、冬至、萬壽等節的家宴。殿內寶座上方有一塊匾,上書“正大光明”四個漂亮的正楷字,其意為公正、光明磊落。這塊匾很有名氣,與秘密立儲關系密切。皇帝生前,親自從皇子中選一個德才兼備的作為皇太子——嗣皇帝,不予宣布,而是由皇帝秘密親書預立皇太子的名字的“御書”,密封匣內,茂于那塊匾后,等皇帝死后或死前,由御前大臣、軍機大臣等共同啟示,按御書所定,嗣皇帝即位。相傳雍正的第四子弘歷即乾隆皇帝,就是這…");
                  quatree.insert(
          new Envelope(new Coordinate(116390673991873)), info5);
                  PointInfo info6 
          = new PointInfo("坤寧宮");
                  quatree.insert(
          new Envelope(new Coordinate(116390673991907)), info6);
                  
          // 幾個離故宮較遠的點
                  PointInfo info7 = new PointInfo("香山公園");
                  quatree.insert(
          new Envelope(new Coordinate(116191513999031)), info7);
                  PointInfo info8 
          = new PointInfo("香山寺");
                  quatree.insert(
          new Envelope(new Coordinate(116191503999039)), info8);
                  PointInfo info9 
          = new PointInfo("眼鏡湖");
                  quatree.insert(
          new Envelope(new Coordinate(116181543999566)), info9);

          當中需要說明的部分如下: 
                   quatree.insert(new Envelope(new Coordinate(11638937, 3992178)), info1);
                    當中的Coordinate代表了一個只是包含經緯度的點(point)。在jts中,還有另外一個專門的對象表示點,就是point對象,但是這里我們只是想用經緯度來建立好節點之間的關系,故而只是采用了Coordinate。
                    而Envelope,這個對象其實代表的是一個矩形框。可能是因為信封就是一個矩形框的原因,所以,加拿大人就用這個單詞來表示矩形了。Envelope的構造函數中需要給出矩形的對角坐標。但是我們這里只是有一個點,所以,jts會把這一個單獨的點也作為一個矩形。
                   這就是說明,jts中結點不是簡單的point,而是一個矩形(Envelope)。
                   至于最后的info,則是表示點的其他描述信息。
                    需要補充的是,jts目前只是支持二維,三維的z坐標永遠是0。

           3. 建立一顆樹的目的不是等待他發芽,而是為了搜索(everyone has his purpose!)

               quatree 提供了三個搜索方法,簽名分別如下: 
                   

          public List query(Envelope searchEnv) {
                  
          /**
                   * the items that are matched are the items in quads which overlap the
                   * search envelope
                   
          */

                  ArrayListVisitor visitor 
          = new ArrayListVisitor();
                  query(searchEnv, visitor);
                  
          return visitor.getItems();
              }


              
          public void query(Envelope searchEnv, ItemVisitor visitor) {
                  
          /**
                   * the items that are matched are the items in quads which overlap the
                   * search envelope
                   
          */

                  root.visit(searchEnv, visitor);
              }


              
          /**
               * Return a list of all items in the Quadtree
               
          */

              
          public List queryAll() {
                  List foundItems 
          = new ArrayList();
                  root.addAllItems(foundItems);
                  
          return foundItems;
              }

            每個函數的含義也是很簡單的,分別表示搜索范圍搜索,范圍過濾搜索和全部搜索。
             接下來我們就分別嘗試分為搜索和范圍過濾搜索:
             范圍搜索很簡單,只要給出一個矩形框,然后傳入就可以了,代碼如下:
            

          // 看看在故宮旁邊能夠找到什么
                  System.out.println("看看在故宮旁邊能夠找到什么");
                  List
          <PointInfo> points = quatree.query(new Envelope(new Coordinate(
                          
          116389373992178)));
                  
          for (PointInfo pointInfo : points) {
                      
          // 結果是什么,居然就是故宮一個結果
                      System.out.println(pointInfo.getName());
                  }

                  
          // 只能夠調整經緯度,來看看故宮周圍有什么
                  System.out.println("=================================");
                  System.out.println(
          "只能夠調整經緯度,來看看故宮周圍有什么,這個就相當于地圖上的周邊搜索的概念");
                  points 
          = quatree.query(new Envelope(new Coordinate(116389373991605),
                          
          new Coordinate(116390813992178)));
                  
          for (PointInfo pointInfo : points) {
                      
          // 結果是什么?
                      System.out.println(pointInfo.getName());
                  }

             可以看到,當只是輸入故宮的點的時候,結果只是一個故宮。所以,我就找了一范圍來搜,模擬文斌在http://www.51ditu.com上實現的那個周邊搜索的概念。結果會是什么呢?
              說起周邊搜索,不可能沒有關鍵詞,比如我們經常在群里說得那個搜索模式,我想知道在上地周邊哪里有好的酒吧,下班后可以去喝一杯!
              這就是周邊過濾搜索的概念了。
               quadtree存在著這樣的一個方法:
               public void query(Envelope searchEnv, ItemVisitor visitor) ,這個當中的ItemVisitor 是一個接口。實現的類似于一個訪問者的功能,挨個詢問過路人:“你可見到戈多,我在等他”!我們可以看一下默認的ArrayListVisitor。看后,也會覺得jts在這個地方多此一舉了。
             
          /**
           * 
          @version 1.7
           
          */

          public class ArrayListVisitor
              
          implements ItemVisitor
          {

            
          private ArrayList items = new ArrayList();
            
          public ArrayListVisitor() {
            }


            
          public void visitItem(Object item)
            
          {
              items.add(item);
            }


            
          public ArrayList getItems() return items; }

          }


           可以看到,這個類對于過路人什么都沒有問。
           接下來,我就仿照著實現一個詢問器,問問那個宮殿中懸掛著“正大光明”牌匾。
           
          public void visitItem(Object item) {
                  PointInfo info 
          = (PointInfo) item;
                  
          if (info.getInfo() != null && !"".equals(info.getInfo())
                          
          && info.getInfo().contains("正大光明")) {
                      items.add(item);
                  }

              }

            最后在quatree中用法如下: 
             
          // 既然可以實現周邊搜索,那么就可以在故宮旁邊搜索那個宮殿中含有正大光明的牌匾
                  System.out.println("=================================");
                  System.out.println(
          "既然可以實現周邊搜索,那么就可以在故宮旁邊搜索那個宮殿中含有正大光明的牌匾");
                  UseArrayListVisitor visitor 
          = new UseArrayListVisitor();
                  quatree.query(
          new Envelope(new Coordinate(116389373991605),
                          
          new Coordinate(116390813992178)), visitor);
                  points 
          = visitor.getItems();
                  
          for (PointInfo pointInfo : points) {
                      
          // 結果是什么?
                      System.out.println(pointInfo.getName());
                  }

                   結果是什么呢,當然就是乾清宮!
                  
                   可以說,Jts是一個優雅的空間實用包,但是如果我在剛才過濾器中搜索的詞不是那么簡單呢,我想向文本搜索一樣牽涉到分詞,排序的概念呢。
                  如果我真的要在中國范圍內找某一個酒吧呢?
                  我對于這些問題的一個思路就是,讓lucene和jts合作!不過這是下一篇博客的內容了。
                  
          posted on 2007-12-21 13:47 張氏兄弟 閱讀(3886) 評論(3)  編輯  收藏 所屬分類: 51ditu.com

          評論:
          # re: jts-空間索引 2007-12-21 13:55 | hidden
          寫得很詳細
          有研究鉆研下lucene...jts  回復  更多評論
            
          # re: jts-空間索引 2007-12-21 15:53 | stanley_xu
          對于任何一個gis查詢系統來說,用sptialIndex去索引多邊形是個必要過程。
          把不同類型的對象用多個si來索引,可以明顯提高搜索效率。  回復  更多評論
            
          # re: jts-空間索引 2007-12-21 18:08 | 祎恬凡
          to: stanley_xu
          兄弟我剛剛到靈圖來,很多東西都要學習。
          對于您說的用sptialIndex來索引多邊形,我還沒有想清楚怎么做!
          如果您肯賜教,不勝感激!
            回復  更多評論
            
          主站蜘蛛池模板: 双流县| 如东县| 政和县| 融水| 灵台县| 石泉县| 台州市| 达日县| 扶余县| 西乡县| 福建省| 库尔勒市| 蚌埠市| 新乡市| 湘阴县| 鄂州市| 高密市| 嘉兴市| 梅河口市| 鹤岗市| 同心县| 富蕴县| 榆中县| 泌阳县| 迁西县| 邻水| 朝阳市| 西乡县| 双城市| 冷水江市| 隆化县| 广德县| 萨迦县| 福鼎市| 雷州市| 南雄市| 英德市| 隆德县| 东乡族自治县| 太仆寺旗| 新干县|