Mapserver その３

#概要
MapserverとPostgisを使って自家製地図サーバを構築してみた。

#地図投影法の知識
球面である地球を平面の地図に投影する図法が、色々方法が考えられています。
しかし、角度（形）と面積を保って、球を平面に投影する地図は無い、という事実が地図学の基本的問題だそうです。
一般的に、統計学は積分をする傾向があるために、正積投影は、統計向きである。一方、正角投影は航海目的に好ましい。
主な投影法を載せます。出典: フリー百科事典『ウィキペディア（Wikipedia）』
①正距円筒図法 
緯経線が直角、等間隔に交差するので方眼図法、正方形図法とも呼ばれる。
この図法は緯度、経度をそれぞれ地図の縦と横にそのまま読み替えたもので、標準緯線上と縦方向に関して正距である。 標準緯線から離れるほど横方向の長さが拡大されるため、面積や角度は正しくない。
GPSなどから得られた緯度、経度の情報を扱う場合、描画処理が簡単であることから、電子地図の図法として用いられることがある。
実際の地球半径（6378km）として1:1の地図を出力すると、縦 20,037km、横40,074kmとなる。
![](https://upload.wikimedia.org/wikipedia/commons/thumb/e/ea/Equirectangular-projection.jpg/350px-Equirectangular-projection.jpg)

②メルカトル図法
1569年、フランドル出身の地理学者ゲラルドゥス・メルカトルがオランダで発表した地図に使われた地図投影法。
円筒図法のひとつでその正角性から正角円筒図法ともいう。1枚の長方形の中に世界全図を書き込む事ができ、経線からの角度が正しい等角図法であるため、海図・航路用地図としてよく使われる。
メルカトルのオリジナルというわけではなく、ドイツのエッラープが1511年に作成した地図にはすでに使われていた。
経度と緯度を格子状に配置させ、緯線と経線の比率を一定に保ったもので、「地球を円筒に投射し、それを書き写したものを長方形に広げ、縦方向に必要に応じて局所的な拡大を加えたもの」と言える。そのため「正角円筒図法」と呼ばれる。
メルカトル図法の地図において、出発地と目的地との間に直線を引いて経線となす角度を測り、コンパスを見ながら常にその角度へ進むようにすれば必ず目的地に到着する。
この性質を正角性という。このコースは航程線と呼ばれ、多くの場合実際の最短距離（大圏コース）から大きく外れるが、舵取りが容易であることから、羅針盤の発明された時代から広く利用されてきた。
![](https://upload.wikimedia.org/wikipedia/commons/thumb/7/74/Mercator-projection.jpg/350px-Mercator-projection.jpg)

③ユニバーサル横メルカトル図法
略してUTM図法 (Universal Transverse Mercator) とも呼ばれる。中縮尺向けの図法である。
日本では国土地理院発行の1:10,000～1:200,000の地形図に使用されている。
通常のメルカトル図法は、極方向に円筒を展開させるため、極地方はあまり正確に投影できないが、赤道付近では比較的正確に投影できる。UTM図法では、これを利用し、通常のメルカトル図法と異なり、円筒面を横に倒して、ある経線を中心にして投影する。これを複数の経線を基準として何度も投影して組み合わせることで、比較的正確な地図が完成する。そのとき、中心経線上での縮尺係数を0.9996として、歪みを軽減している。
また、日本付近では、この中央経線を東経129度、135度、141度としている。6度ごとであるのは、UTM図法の規格である。
![](https://upload.wikimedia.org/wikipedia/commons/thumb/d/df/%E6%A8%AA%E3%83%A1%E3%83%AB%E3%82%AB%E3%83%88%E3%83%AB.png/300px-%E6%A8%AA%E3%83%A1%E3%83%AB%E3%82%AB%E3%83%88%E3%83%AB.png)

④平射方位図法
ステレオ投影のことを平射方位図法、またはステレオ図法と言う。
平射方位図法は正角投影に分類される。地球のどちらかの極を中心に投影したとき、経線は原点から放射状にのび、緯線は原点を中心とする円になるという、望ましい特性が付加される。
![](https://upload.wikimedia.org/wikipedia/commons/thumb/5/58/Stereographic_Projection_Polar.jpg/220px-Stereographic_Projection_Polar.jpg)

#世界測地系と日本測地系の知識
地球上の位置を経度・緯度・標高の座標で表すとき、前提とする条件のことである。
現代では準拠楕円体、測地座標系、標高の基準となるジオイド面の3要素を特定する事により定められる。
測量の前提であり、地図を作成する際には一貫性が求められる。
日本ではベッセル楕円体に準拠し、独自の天文観測による座標系と、東京湾平均海面を基準とした日本測地系と呼ばれる測地系を用いてきた。しかし、日本測地系は日本周辺にしか通用しないことが前提で、例えば米軍のGPSと日本測地系の緯度経度では、東京付近の地表面で400m程度のずれが存在する。
また、日本測地系にもとづく基準点網は古い測量成果の三角網によって設定されているため、測地系以外の要因による地図のゆがみが5～10m程度存在した。
これらのずれやゆがみは、日本国内向けに1:25,000の地形図を発行するには問題を生じないが、海図の国際利用や、精密な位置情報にもとづくGISデータの整備の障害になりつつあった。
そこで、測量法の改正により2002年4月1日から、国際機関で定められ、 陸地の測量に用いる国が多く、 GPSで使用される米国の測地系（WGS84）との座標ずれが少ない 測地系であるITRF（国際地球基準座標系）に準拠した世界測地系を用いることとなった。
東京付近では、おおむね、日本測地系の数値から、北緯に12秒加え、東経に12秒減ずると、世界測地系の数値が得られる。
世界測地系の、準拠楕円体は1980年に定められたGRS80楕円体、測地座標系は地球重心を原点とするITRF94座標系、標高の基準となるジオイド面は東京湾平均海面である。
さらに、1984年に決定されたGPS衛星の成果を盛り込んだWGS84は準拠楕円体が世界測地系と異なるが、2004年現在のWGS84の準拠楕円体はGRS80と短半径が0.1mm異なるだけである。 出典: フリー百科事典『ウィキペディア（Wikipedia）』

#座標変換用ライブラリ
postgisでは、「PROJ.4」という座標変換用ライブラリが投影法と測地系から計算をします。
「PROJ.4」での表記。
主な図法
①正距円筒図法 --longlat
②メルカトル図法 --merc
③ユニバーサル横メルカトル図法--utm
④平射方位図法 --stere
　postgisでは、sridを使います。主なsrid
WGS84--srid--4326
JD2000--srid--4612
TokyoDatum--srid--4301
平面直角座標--srid--2451

#インストール
MapServerのインストールの前に、ApacheとPostgreSQL、PHPがインストールされていることが必要です。
MapServerのインストールの前に、postgisがインストールされていることが必要です。
postgis,mapserverをインストールします。

```
sudo aptitude install postgis mapserver
```


#postgisの動作確認

①データベースを作ります。
postgresqlのスーパーユーザーになります。
データベースを作成します。

```
createdb testgis
```

データベースにpostgis拡張を加えます。

```
createlang plpgsql testgis
```

postgisの関数を加えます。

```
psql -f lwpostgis.sql -d testgis
```

postgisのデータを加えます。

```
psql -f spatial_ref_sys.sql -d testgis
```

②データベースを確認します。

データベースに接続します。

```
psql testgis
```

バージョンの一覧を表示させます。

```
select postgis_full_version();
```

srid4326を表示させます。

```
select * from spatial_ref_sys with srid=4326;
```

③テーブルの作成
test1テーブルを作ります

```
CREATE TABLE test1(  id int4 NOT NULL PRIMARY KEY,  name  varchar(50));
```

テーブルにgeometryカラムを追加します。

```
SELECT AddGeometryColumn(  'test1',   'geom',    4326 ,  'POINT',       2);
```

④データの入力

```
INSERT INTO test1 (id, name, geom) VALUES (1, '板谷', GeometryFromText('POINT( 140.268815 37.811627)',4326));
INSERT INTO test1 (id, name, geom) VALUES (2, '峠', GeometryFromText('POINT(140.236041 37.811935)',4326));
INSERT INTO test1 (id, name, geom) VALUES (3, '大沢', GeometryFromText('POINT(140.198010 37.839775)',4326));
INSERT INTO test1 (id, name, geom) VALUES (4, '関根', GeometryFromText('POINT(140.146284 37.864592)',4326));
INSERT INTO test1 (id, name, geom) VALUES (5, '米沢', GeometryFromText('POINT(140.128209 37.909478)',4326));
INSERT INTO test1 (id, name, geom) VALUES (6, '置賜', GeometryFromText('POINT(140.142496 37.954093)',4326));
INSERT INTO test1 (id, name, geom) VALUES (7, '高畠', GeometryFromText('POINT(140.15281 37.992314)',4326));
INSERT INTO test1 (id, name, geom) VALUES (8, '赤湯', GeometryFromText('POINT(140.148978 38.047081)',4326));
INSERT INTO test1 (id, name, geom) VALUES (9, '中川', GeometryFromText('POINT( 140.203553 38.093349)',4326));
INSERT INTO test1 (id, name, geom) VALUES (10, '羽前中山', GeometryFromText('POINT( 140.218318 38.124158)',4326));
INSERT INTO test1 (id, name, geom) VALUES (11, 'かみのやま温泉', GeometryFromText('POINT( 140.27867 38.152259)',4326));
INSERT INTO test1 (id, name, geom) VALUES (12, '茂吉記念館前', GeometryFromText('POINT( 140.298167 38.171249)',4326));
INSERT INTO test1 (id, name, geom) VALUES (13, '蔵王', GeometryFromText('POINT( 140.303299 38.20592)',4326));
INSERT INTO test1 (id, name, geom) VALUES (14, '山形', GeometryFromText('POINT(140.327253 38.248098)',4326));
INSERT INTO test1 (id, name, geom) VALUES (15, '北山形', GeometryFromText('POINT(140.332658 38.265902)',4326));
INSERT INTO test1 (id, name, geom) VALUES (16, '羽前千歳', GeometryFromText('POINT(140.342168 38.287313)',4326));
```

⑤検索

経度140.144556 緯度37.913004から近い順に駅を表示する。単位はメートル。

```
SELECT id, name, ST_distance_sphere(geom,  GeometryFromText('POINT(140.144556 37.913004)', 4326)) as d FROM test1 ORDER BY d;
```


#空間データ基盤とは
国土空間データ基盤は、空間データのうち基盤的なものを指し、国土全体の地勢や行政界等の基盤的な地図データである「空間データ基盤」、空間データ基盤に結びつけて利用される統計・台帳情報等のうち、公共的観点から基本的なデータである「基本空間データ」、航空写真や衛星画像等から作成される「デジタル画像」の３つの要素から構成される平成７年１月に発生した阪神・淡路大震災において、関係機関が保有するデータを相互に利用するシステムがなかったため、早期の被害状況の把握、震災直後の救援活動の支援、復興の支援等を迅速かつ効率的に進めることができなかったことが事後の大きな反省として提起された。
国は、国土空間データ基盤の整備、地理情報の規格化・標準化、行政サービスの電子化に乗り出した。
2007年度から、地理空間情報活用推進基本法の成立を受け、GISにおける共通白地図として誰もが利活用可能な基盤地図情報の整備が始まり、整備の終わったものから順次国土地理院のウェブサイト(http://www.gsi.go.jp/kiban/) を通じて供覧及びデータ提供がされている。
空間データ基盤に該当する項目
 測地基準点 国家基準点、公共基準点 
 標高、水深 格子点の標高、水深、島しょの標高 
 交通 道路区域界、道路中心線、鉄道中心線、航路 
 河川、海岸線等 河川区域界、水涯線、海岸線、湖沼、低潮線（干出線）、河川中心線 
 土地 筆界等、森林区画界 
 建物 公共建物及び一般建物 
 位置参照情報 地名に対応する位置参照情報、行政区画、統計調査区、住 所に対応する位置参照情報、標準地域メッシュ 
 公園等 公園、飛行場 
 画像情報 

#G-XMLとは何か
平成１１年３月「国土空間データ基盤標準及び整備計画」を策定し、国土空間データ基盤に関する技術的な標準（地理情報標準）、利用頻度が高く、社会的効果が大きい等の観点で選定した標準的なデータ項目（空間データ基盤標準）の二つの標準を「国土空間データ基盤標準」として定めた。
地理情報標準は、ＧＩＳの基盤となる空間データを、異なるシステム間で相互利用する際の互換性の確保を主な目的に、データの設計、品質、記述方法、仕様の書き方等のルールを定めたもの、空間データの整備等に必要な基本項目について、ISO/TC211の国際標準（案）を基に、国土地理院と民間企業との官民共同研究により、平成１１年３月に第１版、平成１４年３月に第２版を作成しました。
地理情報標準は、基になった国際標準案が国際標準確定後、順次ＪＩＳ（日本工業規格）にしています。
平成１７年３月にはＪＩＳ化された最新の地理情報標準と国際標準に準拠し、内容を実利用に即して絞り体系化した、より実用的な「地理情報標準プロファイル（JPGIS）」を作成した。
関連する標準として、インターネット上で地理情報を相互流通させるためのプロトコルであるＧ－ＸＭＬをＪＩＳ化した。
空間データを記述するXMLがG-XMLだ。レベル25000、レベル2500、レベル500がある。
レベル2500は全県そろっていない。レベル500は未整備。

#入手方法
国土地理院　基盤地図情報ダウンロードサービスhttp://fgd.gsi.go.jp/download/
から入手可能。
 基盤地図情報基本パッケージ 
 基準点等パッケージ 
 行政区画等パッケージ 
 水系パッケージ 
 構造物等パッケージ 
がある。

①縮尺レベル25000を選択。
②山形県を選択。
　基盤地図情報（縮尺レベル25000）
  山形県
          海岸線
          行政区画の境界線及び代表点
          道路縁
          軌道の中心線
          標高点（数値標高モデルを除く）
          水涯線
          建築物の外周線
               
③水涯線を選択。
④FG-GML-06-10-Z001.zipを ダウンロード 
⑤解凍する。
FG-GML-06-WL25000-20080331-0001.xmlが得られる。

#データベースの設計

①G-XMLから得られるデータ
記号に沿ってテーブルを作る。
1.測量の基準点			「GCP」		点
2.標高点				「ElevPt」	点
3.等高線				「Cntr」		線
4.行政区画			「AdmArea」	面
5.行政区画界線			「AdmBdry」	線
6.行政区画代表点		「AdmPt」 	点
7.町字界線			「CommBdry」	線
8.町字の代表点			「CommPt」	点
9.街区域				「SBArea」	面
10.街区線				「SBBdry」	線
11.街区の代表点		「SBAPt」		点
12.水域				「WA」		面
13.水涯線				「WL」		線
14.海岸線				「Cstline」	線
15.河川堤防表法肩法線	「LeveeEdge」	線
16.河川区域界線		「RvrMgtBdry」	線
17.建築物				「BldA」		面
18.建築物の外周線		「BldL」		線
19.道路縁				「RdEdg」
20.道路区域界線		「RdMgtBdry」	線
21.軌道の中心線		「RailCL」	線

②その他のデータ
idのみ使用。
基盤地図情報地物(FGD Feature)－ FGDFeature
地物 ID(Feature ID)fid
存在期間_自(Life Span From)lfSpanFr
存在期間_至(Life Span To)lfSpanTo
整備完了日(Development Date)devDate
出典地図情報レベル(Original GeographicInformation Level)orgGILvl
出典メタデータID(Original Metadata ID)orgMDId
測量の基準点(Geodetic Control Point)－ GCP
地点(Position)pos
助言番号(Advice number)advNo
計画機関名(Organization Name)orgName
種別(Type)type
等級種別(GCPClass)gcpClass
基準点コード(GCP Code)gcpCode
点名称(GCP Name)name
B （緯度を意味する）(Breite)BL （経度を意味する）(Laenge)L
標高(Altitude)alti
標高値有効小数桁数(Altitude Accuracy)altiAcc

③テーブルの設計
代表として、水涯線テーブルを記述。

```
DROP TABLE wl;
CREATE TABLE wl( kid varchar(50) ) WITH OIDS;
SELECT AddGeometryColumn ( 'wl', 'geom', -1 , 'LINESTRING', 2 );
```

#空間データ基盤の利用
mapserver動作確認

①ブラウザを開いて、次のURLを打つ

```
http://server/cgi-bin/mapserv
```

No query information to decode. QUERY_STRING is set, but empty.
以上が表示されれば、mapserverは稼動しています。

②エディタで次のコードを入力します。

test1.map

```
MAP
  NAME  'test'
  EXTENT 0 0 200 200
  STATUS ON
  SIZE 200 200  
  IMAGETYPE PNG
  LAYER
    NAME 'line1'
    TYPE LINE
    STATUS DEFAULT
    FEATURE
      POINTS 10 10 10 60 60 60 60 10 10 10 END
      POINTS 100 100 150 150 150 100 100 100 END
    END
    CLASS
      SYMBOL 'circle'
      SIZE 5
      COLOR 255 0 0
    END
  END
  SYMBOL 
    NAME 'circle'
    TYPE ELLIPSE
    POINTS 1 1 END
    FILLED TRUE
  END
END
```

③cgi-binに設置します。

④表示確認。
ブラウザを開いて、次のURLを打つ

```
http://server/cgi-bin/mapserv?map=test1.map&mode=map
```

画像が表示されれば、mapserverは稼動しています。

#空間データ基盤の解析

GMLは、以下のような書式です。

```
<?xml version="1.0" encoding="Shift_JIS"?>
<Dataset xsi:schemaLocation="http://fgd.gsi.go.jp/spec/2008/FGD_GMLSchema FGD_GMLSchema.xsd" 
	xmlns:gml="http://www.opengis.net/gml/3.2" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:xlink="http://www.w3.org/1999/xlink"
    xmlns="http://fgd.gsi.go.jp/spec/2008/FGD_GMLSchema"
    gml:id="Dataset1">
  <gml:description>基盤地図情報メタデータ ID=fmdid:7-26</gml:description>
  <gml:name>基盤地図情報ダウンロードデータ（GML版）</gml:name>
<WL  gml:id="K13_41387">
<fid>fgoid:10-00100-7-19-402979</fid>
<lfSpanFr gml:id="K13_41387-1">
<gml:timePosition>2008-03-31</gml:timePosition>
</lfSpanFr>
<devDate gml:id="K13_41387-2">
<gml:timePosition>2008-03-31</gml:timePosition>
</devDate>
<orgGILvl>25000</orgGILvl>
<orgMDId>0-8</orgMDId>
<loc>
<gml:Curve gml:id="K13_41387-g" srsName="fguuid:jgd2000.bl">
<gml:segments>
<gml:LineStringSegment>
<gml:posList>
 38.3286875 139.8603275
 38.328726944 139.860346667
 38.328751111 139.860386944
 38.328741944 139.860434722
 38.328710278 139.860455833
 38.328658889 139.860450278
 38.328618333 139.860429167
 38.328601667 139.860392778
 38.328616667 139.860350556
 38.328643889 139.8603275
 38.3286875 139.8603275
</gml:posList>
</gml:LineStringSegment>
</gml:segments>
</gml:Curve>
</loc>
<type>その他</type>
<name></name>
</WL>
</Dataset>
```

gml:id　と　gml:posListを取得し、POSTGISに投入します。

#空間データ基盤の変換

ここでは、次のコードでGMLからPGSQLを生成します。
test.vbs

```
Dim objDOM, res, nodeList, obj, fso, stream
Set fso = CreateObject("Scripting.FileSystemObject")
Set stream = fso.CreateTextFile("test.sql")
Set objDOM = CreateObject("MSXML2.DOMDocument") 
res = objDOM.load("FG-GML-06-WL25000-20080331-0001.xml") 
If res = True Then 
   Set nodeList = objDOM.documentElement.selectNodes("/Dataset/WL/loc") 
   For Each obj In nodeList 
      kid = obj.parentNode.getAttribute("gml:id")
      text = obj.text
      test = replace(text, vblf, "")
      lines = Split(test, " ")
      j = UBound(lines) / 2
      sql = "INSERT INTO wl (kid, geom) VALUES ('" & kid & "', GeometryFromText('LINESTRING(" 
      For i = 0 to j 
       sql = sql & lines(i * 2 + 1) & " " & lines(i * 2) & "," 
      Next
      sql = Left(sql, Len(sql) - 1)
      sql = sql & ")',-1));"
      stream.WriteLine ( sql )
   Next 
End If 
stream.Close()
Set objDOM = Nothing 
Set fso = Nothing 
MsgBox "ok"
```

使い方
①ダウンロードしたフォルダにtest.vbsをコピーします。
②FG-GML-06-WL25000-20080331-0001.xmlがあることを確認します。
③vbsをダブルクリックします。
④一分位で、test.sqlが生成されます。

#空間データ基盤の投入テスト

postgis,mapserver動作確認
①テストテーブルの作成

```
CREATE TABLE test2 ( kid varchar(50) ) WITH OIDS;
SELECT AddGeometryColumn ( 'wl', 'geom', -1 , 'POINT', 2 );
```

②テストデータの投入

```
INSERT INTO test2 (kid, geom) VALUES ('kid_0', GeometryFromText('POINT(139.0 38.0),-1);
INSERT INTO test2 (kid, geom) VALUES ('kid_1', GeometryFromText('POINT(139.1 38.1),-1);
INSERT INTO test2 (kid, geom) VALUES ('kid_2', GeometryFromText('POINT(139.2 38.2),-1);
INSERT INTO test2 (kid, geom) VALUES ('kid_3', GeometryFromText('POINT(139.3 38.3),-1);
```

③mapファイルの作成

```
MAP
  NAME TEST2
  STATUS ON
  SIZE 500 500
  EXTENT 139 37.5 140.5 38.5
  IMAGECOLOR  255 255 128
  UNITS dd
  IMAGETYPE png
  LAYER
    NAME "point"
    CONNECTIONTYPE postgis
    CONNECTION "user=**** password=**** dbname=testgis1 host=localhost"
    DATA "geom FROM test2"
    STATUS DEFAULT
    TYPE POINT
    CLASS
      STYLE
        SYMBOL 'circle'
        SIZE 5
        COLOR 255 0 0
      END
    END
  END
  SYMBOL
    NAME 'circle'
    TYPE ELLIPSE
    POINTS 1 1 END
    FILLED TRUE
  END
END
```

④cgi-binに設置します。

⑤表示確認。
ブラウザを開いて、次のURLを打つ

```
http://server/cgi-bin/mapserv?map=test2.map&mode=map&scale=1000000&mapxy=139.0+38.0
```

画像が表示されれば、postgisとmapserverが連携しています。

#空間データ基盤の投入

作成したtest.sqlをサーバーにアップし、pgsql -d testgis1 -f test.sqlで投入する。

表示確認

①test3.mapを作成する。

```
MAP
  NAME TEST
  STATUS ON
  SIZE 500 500
  EXTENT 139 37.5 140.5 38.5
  IMAGECOLOR  255 255 128
  UNITS dd
  IMAGETYPE png
  SCALEBAR
    STATUS embed
    STYLE 1
    UNITS meters
    COLOR 0 0 0
    SIZE 200 10
    INTERVALS 2
  END
  LAYER
    NAME "mizu"
    CONNECTIONTYPE postgis
    CONNECTION "user=*** password=*** dbname=testgis1 host=localhost"
    DATA "geom FROM wl"
    STATUS DEFAULT
    TYPE LINE
    CLASS
      STYLE
        SYMBOL 'circle'
        SIZE 2
        COLOR 0 191 255
      END
    END
  END
  LAYER
    NAME "point"
    CONNECTIONTYPE postgis
    CONNECTION "user=*** password=*** dbname=testgis1 host=localhost"
    DATA "geom FROM test2"
    STATUS DEFAULT
    TYPE POINT
    CLASS
      STYLE
        SYMBOL 'circle'
        SIZE 5
        COLOR 255 0 0
      END
    END
  END
  SYMBOL
    NAME 'circle'
    TYPE ELLIPSE
    POINTS 1 1 END
    FILLED TRUE
  END
END
```

②cgi-binに設置します。

③表示確認。
ブラウザを開いて、次のURLを打つ

```
http://server/cgi-bin/mapserv?map=test3.map&mode=map&scale=1000000&mapxy=139.0+38.0
```

画像が表示されれば、成功です。

![](https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcR0x_JbmxPFoesDBMhJVnsQJ1M_zAcJYMR71P-TOy5dvoE9zfL9)