Geoserverが可能にするスタイリッシュなマップ作成

geoserver_thm.png

 企業か個人かを問うことなく、独自のデータを地図上に展開してインターネット上で公開するというWebサービスを簡単に利用可能にしたのは、Google Mapsが先鞭を付けた功績としていいだろう。しかしながらGoogle Mapsでは扱えない種類のデータも存在し、あるいはマップの細部を自由にユーザ指定したいという場合は、その他のオプションも検討しなくてはならない。その1つが本稿で紹介するGeoserverだ。

 Geoserverは、Open Geospatial Consortiumの提唱するWeb Feature ServerおよびWeb Coverage Serverという仕様を実装しており、両者をWeb Map Serverという1つの形に統合している。現行の安定版は1.6.5であるが、開発陣からは1.7.0-RC2がリリースされたところだ。その記述言語にはJavaが採用されており、Linux/Unix系OSおよびWindowsにて利用できるが、その他の要件としてSun JRE 6などのJava Runtime Environmentも必要となる。

 Geoserverのインストールは、TomcatやJettyなどのサーブレットコンテナに対して行えばいいが、開発サイドからはスタンドアローン型のバイナリパッケージも提供されている。例えばUbuntuの場合、バイナリパッケージを用いてGeoserverをインストールするには「sudo unzip geoserver-1.6.4-bin.zip-d /usr/local/」というコマンドを実行するだけだ。

 Geoserverを使用するにあたっては、各自のシェルにて$GEOSERVER_HOMEの定義をしておく必要がある。例えばbashを使用している場合は、「export GEOSERVER_HOME=/usr/local/geoserver」を.bashrcあるいは.bash_profileの末尾に追加しておけばいい。

 Geoserverを起動させるには、「$GEOSERVER_HOME/bin/startup.sh」と入力する。スタートプロセスの終了後(このプロセスは数分程度の時間を要する場合もある)、Webブラウザを開いてhttp://127.0.0.1:8080/geoserverにアクセスすると、サーバの設定およびデモページが表示されるはずだ。

geoserver1_thumb.png
Geoserverの設定およびデモページ

 このページにてAdminリンクをクリックすると、サーバのステータス情報が表示され、Configリンクをクリックすると、コントロールパネルにログインされる。一部の例外もあるが、基本的にGeoserverの設定ページでは、Apply、Save、Loadボタンを囲んだボックスが、ページ左上に表示されるようになっている。このうちApplyは、サーバ設定の変更を有効化するためのボタンで、これをクリックするまで変更内容はサーバに適用されない。同じくSaveは変更内容をディスクに書き出すためのボタンであり、Loadはディスクに保存した設定を読み込むためのボタンで、適用はしたが保存はしていない状態の設定変更をキャンセルしたければ、後者のボタンを使用すればいい。

データの準備

 Geoserverのインストールと起動が正常に行えたら、そこで処理するためのデータの準備をする必要がある。Geoserverは、他のWeb Feature Serverおよび、PostgreSQLデータベースからPostGIS機能拡張を介してデータを読み込む機能も備えているが、より手早くデータを準備したければ、ローカルに保存されるshapefileを利用する方が簡単なはずだ。フリーで利用できるGISデータのソースとしては、TIGER/Line shapefilesというデータが米国勢調査局(US Census Bureau)から公開されており、これらのファイルには、道路、鉄道、海岸線、州や郡の境界線といった“地物”(feature:地図上に表記すべきオブジェクト)の情報が収められている。本稿の作成例では、メリーランド州フレデリック郡の道路情報に簡単なスタイル指定を加えたものを表示させてみるが、ここで用いるデータの詳細を確認したい場合はQgisなどのプログラムが必要となる。

 具体的な手順としては、事前に「unzip fe_2007_24021_edges.zip -d $GEOSERVER_HOME/data_dir/data/shapefiles/」というコマンドを用いてshapefileを解凍しておき、その後Geoserverのコントロールパネルに移動してログインをし、Dataをクリックする。最初に行う必要があるのは、各種のデータセットを保持させるNamespaceの作成であるが、この操作については、Namespace→Newの順番で操作ボタンをクリックすればいい。本稿の作例で扱うのはフレデリック郡(Frederick County)の地図データなので、ここでのNamespaceの接頭辞はFrCoとしておこう。次にNewをクリックして、NamespaceのURI(通常はデータの適用先のドメイン名)および、Namespace接頭辞を入力するが、この作例の場合は、ループバックアドレスのhttp://127.0.0.1/FrCoを指定しておけばいい。そして最後にSubmitをクリックする。

 データ格納用のNamespaceを作成したら、次にDataStoreを追加する必要があり、この作例ではTIGER shapefileを使用する。それにはまず、データの設定ページに戻ってDataStoresをクリックする。ここで再度Newをクリックし、Feature Data Set IDボックスにFrederickCountyLinesなどの名称を入力して、ドロップダウンメニューからShapefileを選択する。サーバによるデータのオンライン使用を許可するには、Enabledボックスがオンにされている必要がある。またこの作例については、Namespaceが未設定の場合はFrCoを指定し、urlボックスには「file:data/shapefile/fe_2007_24021_edges.shp」と入力しておく。最後に、その下側にあるcreate spatial index→trueを選択して、Submitをクリックする。

 以上の操作が終了すると、先に指定したデータの詳細を設定するFeatureType Configurationページが開かれているはずである。shapefileのファイル名だけでは、その内容が判別できないこともあるので、地物に対してFrederickCountyLinesというエイリアス(別名)を与えておこう。この作例の地物に対しては、表示形態をGeoserverに指定するStyleをまだ設定していないので、ここではドロップダウンメニューからline styleを選択しておく。

 次に行うべき作業は、データがベースとしている空間的基準システム(SRS:Spatial Reference System)の指定であり、これは幾何モデル(geometric model)とも呼ばれる。SRSの役割は、マッピングに用いる座標系、地球の形状モデル、投影法を記述することであるが、European Petroleum Survey Group(EPSG)が公開しているSRSカタログの場合は、独自に定められたEPSG番号で参照可能なシステムとなっている。ここの作例で使用するTIGERデータのEPSGカタログ番号は4269なので、この番号をSRSボックスに入力してLookup SRSをクリックする。

 Generateボタンをクリックすると、データのバウンディングボックスがGeoserverにより自動描画されるので、Submitが表示される位置まで画面をスクロールして、これをクリックする。

geoserver2_thumb.png
スタイル適用前のマップ

 必要な変更を加えた場合、その適用結果を確認するには、初期画面に戻ってDemoおよびMap Previewのリンクをクリックしなければならない。これにより利用可能なFeatureTypeが一覧されるが、ここでのFrCo:FrederickCountyLinesはリストの最上部付近に表示されるはずだ。この項目をクリックすると、ここでインポートしたデータを基にしたOpenLayersマップをGeoserverが表示してくれる。

 ただし現在の設定下で描画されるマップは、該当する地域を見知った人間でない限り意味不明な、複雑に錯綜する曲線の集合体と化しているはずだ。このようなマップが表示されるのは、それなりの理由が存在する。つまりshapefileには、道路、鉄道、河川などの様々な地物の情報が格納されているのだが、実は先に選択したline styleという指定は、Geoserverに対して「これら地物を単純な線画ですべて描画せよ」という指示を意味していたのである。これを実用性のある地図とするには、マップの表示スタイルを定義しなくてはならない。

マップのスタイル指定

 Geoserverで描画されるマップの外観は、Open Geospatial Consortiumの定めたStyled Layer Descriptor(SLD)によって制御される仕様となっている。SLDの実体は、個々の地物を描画するための規則を記述したXMLドキュメントである。下記のサンプルは簡単なものであるが、基本的にSLDにはこうした情報が収められている。

<?xml version="1.0" encoding="ISO-8859-1"?>
<StyledLayerDescriptor version="1.0.0"
		xsi:schemaLocation="http://www.opengis.net/sld StyledLayerDescriptor.xsd"
		xmlns="http://www.opengis.net/sld"
		xmlns:ogc="http://www.opengis.net/ogc"
		xmlns:xlink="http://www.w3.org/1999/xlink"
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

	<NamedLayer>
		<Name>Frederick County</Name>
		<UserStyle>
			<Title>Frederick County Road Map Style</Title>
			<Abstract>A style for a road map of Frederick County</Abstract>
			<FeatureTypeStyle>

				<Rule>
					<Name>Highways</Name>

					<ogc:Filter>
						<ogc:PropertyIsEqualTo>
							<ogc:PropertyName>MTFCC</ogc:PropertyName>
							<ogc:Literal>S1100</ogc:Literal>
						</ogc:PropertyIsEqualTo>
					</ogc:Filter>

					<!-- black outline -->
					<LineSymbolizer>
						<Stroke>
							<CssParameter name="stroke">#000000</CssParameter>
							<CssParameter name="stroke-width">5</CssParameter>
						</Stroke>
					</LineSymbolizer>
					<!-- red centerline -->
					<LineSymbolizer>
						<Stroke>
							<CssParameter name="stroke">#FF0000</CssParameter>
							<CssParameter name="stroke-width">3</CssParameter>
						</Stroke>
					</LineSymbolizer>
				</Rule>

		  </FeatureTypeStyle>
		</UserStyle>
	</NamedLayer>
</StyledLayerDescriptor>

 例えばこのファイルの場合、ハイウェイを示すラインは、黒い縁取りの赤線で表示するよう指定をしている。そしてこれを具体的に記述しているのが、1組のFilterパートと2組のLineSymbolizerパートなのだ。

 Filterパートの役割は、描画規則の適用先とするFeatureTypeのデータクラスを特定することである。このサンプルの場合で言うと、ハイウェイ(国勢調査局の分類では主要道路)であるかの判定をさせている。shapefile内部において、これに該当する地物を指定しているのは、MAF/Tiger Feature Class Code(MTFCC)のS1100という分類コードだ。なお、Filterパートにおけるこうしたプロパティ名は、大文字と小文字が区別される仕様となっている。

 LineSymbolizerパートの役割は、描画線の表示スタイルを指定することである。自分でこうしたパートを記述する際には、オブジェクトを重ねた絵を描く場合と同様の発想で、「最後に描画したものが地図上では一番手前に表示される」という点を押さえておかなくてはならない。このサンプルの場合で言うと、“黒い縁取りの赤線”というスタイルを定義するにあたっては、最初に5ピクセル幅の黒線を描き、次にその上に3ピクセル幅の赤線を重ねて描くという手順を踏ませている。

 SLDではその他にも、ポリゴンなど領域表示用の幾何図形を扱うPolygonSymbolizer、ポイントデータを扱うPointSymbolizer、ラベルのテキスト形式を扱うTextSymbolizer、衛星写真や数値標高モデルのラスタデータを扱うRasterSymbolizerを指定できる。こうしたSLD仕様については、詳細な説明が公開されているので、別途ダウンロードして確認して頂きたい。

 自分でSLDを作成した場合は、任意の場所に保存しておけばいい。次にGeoserverのデータ設定ページに戻り、StyleおよびNewの順番でクリックして、新規スタイル名の指定用ダイアログを表示させる。この作例の場合はFrederickCountyRoadsと入力して、Submitをクリックする。これによりGeoserverからは、新規のスタイルを入力するためのテキストボックスが表示される。このテキストボックスには先のスタイル指定をコピー&ペーストしておけばいいが、あるいはテキストボックスの下部にある操作ボタンを利用すれば、事前にローカルで作成しておいたコピーをアップロードすることもできるので、その後でSubmitをクリックする。デフォルト設定下のGeoserverでは、指定されたSLDのSLDスキーマに対する有効性を検証するようになっているが、エラーが特定された場合は、SLD中の問題部分を示したページが表示されるので、それを基にしてエラーの修正を行う必要がある。

 次に、ここの作例で使うFrCo:FrederickCountyLinesのFeatureType設定に戻り、SLDの描画設定をlinesからFrederickCountyRoadsに変更して、Submit→Applyの順番でクリックすると、SLDの変更内容がサーバに認識されるようになる。この状況で再びマップビュワーを確認すると、先に見たような錯綜する線画の地図ではなく、東西方向に走る70号線および地図の中央部付近から南東方向に伸びる270号線という、ハイウェイだけが描画された地図に変化しているはずだ。1番目の作例に比べると、この2番目の作例は極端なまでに単純化され尽くした地図になるが、Geoserverにおける地物の表示制御の基礎は理解して頂けたと思う。

 以下に掲載したのは、ハイウェイ以外の道路も描画させるためのSLDだが、ここでは道路の種類ごとに表示スタイルを切り替えさせているため、その分だけ複雑化している。

<?xml version="1.0" encoding="ISO-8859-1"?>
<StyledLayerDescriptor version="1.0.0"
		xsi:schemaLocation="http://www.opengis.net/sld StyledLayerDescriptor.xsd"
		xmlns="http://www.opengis.net/sld"
		xmlns:ogc="http://www.opengis.net/ogc"
		xmlns:xlink="http://www.w3.org/1999/xlink"
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

	<NamedLayer>
		<Name>Frederick County</Name>
		<UserStyle>
			<Title>Frederick County Road Map Style</Title>
			<Abstract>A style for a road map of Frederick County</Abstract>
			<FeatureTypeStyle>

				<Rule>
					<Name>Secondary Roads Low and Med Res</Name>

					<ogc:Filter>
						<ogc:PropertyIsEqualTo>
							<ogc:PropertyName>MTFCC</ogc:PropertyName>
							<ogc:Literal>S1200</ogc:Literal>
						</ogc:PropertyIsEqualTo>
					</ogc:Filter>

					<MinScaleDenominator>15000</MinScaleDenominator>
					<!-- 2 px. black line -->
					<LineSymbolizer>
						<Stroke>
							<CssParameter name="stroke">#000000</CssParameter>
							<CssParameter name="stroke-width">2</CssParameter>
						</Stroke>
					</LineSymbolizer>

				</Rule>

				<Rule>
					<Name>Secondary Roads high res</Name>
					<ogc:Filter>
						<ogc:PropertyIsEqualTo>
							<ogc:PropertyName>MTFCC</ogc:PropertyName>
							<ogc:Literal>S1200</ogc:Literal>
						</ogc:PropertyIsEqualTo>
					</ogc:Filter>

					<MaxScaleDenominator>14999</MaxScaleDenominator>

					<!-- black boundary -->
					<LineSymbolizer>
						<Stroke>
							<CssParameter name="stroke">#000000</CssParameter>
							<CssParameter name="stroke-width">5</CssParameter>
						</Stroke>
					</LineSymbolizer>
					<!-- white stripe -->
					<LineSymbolizer>
						<Stroke>
							<CssParameter name="stroke">#FFFFFF</CssParameter>
							<CssParameter name="stroke-width">3</CssParameter>
						</Stroke>
					</LineSymbolizer>

				</Rule>

				<Rule>
					<Name>Highways</Name>

					<ogc:Filter>
						<ogc:PropertyIsEqualTo>
							<ogc:PropertyName>MTFCC</ogc:PropertyName>
							<ogc:Literal>S1100</ogc:Literal>
						</ogc:PropertyIsEqualTo>
					</ogc:Filter>

					<!-- black outline -->
					<LineSymbolizer>
						<Stroke>
							<CssParameter name="stroke">#000000</CssParameter>
							<CssParameter name="stroke-width">5</CssParameter>
						</Stroke>
					</LineSymbolizer>
					<!-- red centerline -->
					<LineSymbolizer>
						<Stroke>
							<CssParameter name="stroke">#FF0000</CssParameter>
							<CssParameter name="stroke-width">3</CssParameter>
						</Stroke>
					</LineSymbolizer>
				</Rule>

		    </FeatureTypeStyle>
		</UserStyle>
	</NamedLayer>
</StyledLayerDescriptor>

 このSLDでは、ハイウェイだけでなく周辺道路に対するスタイル指定も行っている。また周辺道路については、マップの解像度(縮尺)に応じた2種類の規則が設けてある。最初のハイウェイオンリーのファイルに代えてこのファイルを適用させるには、FrederickCountyRoads SLDの内容を置き換え、変更内容を反映させてから、マップビュワーでの再描画をすればいい。こうして作成されたハイウェイと周辺道路が描画されたマップについては、ズームインをかけると、周辺道路の表示スタイルが切り替わるようになっている。

 解像度に応じた切り替えを担っているのは、MinScaleDenominatorおよびMaxScaleDenominatorという2つのタグである。先に見たFilterの役割が、各規則の適用対象となるデータを判定することであるのに対して、これら2つのタグは、どのようなマップの表示スケールを適用対象とするかの判定を行う。この機能を使うと、マップ上にどこまで詳細な情報を表示させるかを制御でき、ズームアウト時のマップにおける過剰な情報表示といった事態を避けることができる。それには、ズームイン状態では詳細レベルを高め、ズームアウト状態では詳細レベルを低めるという設定を施せばよく、MinScaleDenominatorには規則を適用する最大ズームレベルを、MaxScaleDenominatorにはその下限を指定しておく。実際この作例における周辺道路の描画規則も、マップの縮尺(scale denominator)が15,000以上となる広域地図用のものと、同じく14,999以下となる狭域地図用のものの2つに分けている。

ラベル

 次に更なる改良として、道路に対するラベルの追加を行うことにする。下記のコードは、高解像度時の周辺道路に関する描画規則であるが、マップ表示の煩雑化を回避するため、その追加位置は最初のLineSymbolizerの直前にしておく必要がある。

		<TextSymbolizer>
						<Label>
							<ogc:PropertyName>FULLNAME</ogc:PropertyName>
					 	</Label>

						<Font>
							<CssParameter name="font-family">Times New Roman</CssParameter>
							<CssParameter name="font-style">Normal</CssParameter>
							<CssParameter name="font-size">10</CssParameter>
						</Font>

						<LabelPlacement>
						  <LinePlacement>
						    <PerpendicularOffset>10</PerpendicularOffset>
						 </LinePlacement>
						</LabelPlacement>

						<Halo>
							<Radius>
								<ogc:Literal>2</ogc:Literal>
							</Radius>
							<Fill>
								<CssParameter name="fill">#FFFFFF</CssParameter>
								<CssParameter name="fill-opacity">0.85</CssParameter>
							</Fill>
						</Halo>

						<Fill>
							<CssParameter name="fill">#000000</CssParameter>
						</Fill>
						<VendorOption name="group">yes</VendorOption>
					</TextSymbolizer>

geoserver3_thumb.png
スタイル適用後のマップ(道路の描き分けとラベルの表示)

 TextSymbolizerの役割の一部はLineSymbolizerと共通しているが、独自の機能も有している。まずLabelタグの役割は、地物の名称としてGeoserverが参照すべきshapefile中のフィールドを指定することである。同じくLabelPlacementおよびその子タグの役割は、地物の描画線に対するラベルの表示位置を指定することで、ここでは10ピクセル分のオフセットを設けている。Haloタグの役割は、地物とラベルが重なる際の視認性を高めるために、ラベルの周囲を白抜き表示させることで、ここでは2ピクセルという値を指定している。最後のVendorOptionタグはGeoserver固有の規則であり、これは道路区分のようなラベルの共通する地物が複数存在した場合に、重複したラベル表示をさせないための指定を行う。実際にこの追加コードを挿入したものをSubmitして、変更内容を適用させ、マップビュワーにて再表示をすることで、この変更がもたらす結果を確認して頂きたい。

GetFeatureInfoテンプレート

 その他にもGeoserverには、ユーザから出されるクエリに応じて、FeatureTypeのデータ表示を制御する機能も用意されている。より具体的には、マップビュワー上で道路などの地物をクリックすると、WFS GetFeatureInfoリクエストが実行されて、該当する地物の情報が取得されるという機構である。ただしデフォルト設定下のGeoserverが行う反応は、指定された地物に関するすべてのデータフィールドを収めたテーブルを送信するというものなので、このままでは不要な情報までもがマップビュワー上で表示されてしまう。こうしたデフォルトの挙動を上書きする場合は、Freemarkerテンプレートを利用すればいい。Freemarkerは地物データの読み込みに対応しているが、その他にもいくつかの特長を有しており、特に役立つのは、簡単なものながらループおよびIf-Then-Else分岐をサポートしている点だ。

 下記のサンプルは、先に設定したFeatureTypeに対する簡単なFreemarkerテンプレートで、ここでは道路名だけでなく、そのMTFCCおよび中央分離帯の有無を表示させるようにしている。

<#list features as feature>
  <#if feature.MTFCC.value = "S1200" || feature.MTFCC.value = "S1100">
    <p><b>Road name:</b> ${feature.FULLNAME.value}</p>
    <p><b>MAF/TIGER Feature Class Code:</b> ${feature.MTFCC.value}</p>
    <#if feature.DIVROAD.value = "Y">
      <p>This is a divided road.</p>
    </#if>
  </#if>
</#list>

 このテンプレートを使用するには、上記のコードを収めたファイルを「$GEOSERVER_HOME/data_dir/featureTypes/FrederickCountyLines_fe_2007_24021_edges/content.ftl」に保存しておく。なお新規のテンプレートについては、ここで用いたFeatureTypeにおいて地物のクエリ処理を行う際にGeoserverによって自動で適用されるため、この変更に関する適用操作を別途行う必要はない。

 クエリを受信したGeoserverは、指定された地物(交差点や高架などの場合は地物のセット)に対して、テンプレートの<#list>ディレクティブ部に記述された一連の処理を施す。提出されたクエリへの応答に用いるデータは、地物を示す各インスタンスが保持しているが、これらにアクセスするには、feature.FieldName.valueというようにドット区切りの指定をする仕様となっている。なお先に見たスタイル用のFilterと同様に、こうしたFeatureTypeのデータフィールドに対する参照指定でも大文字と小文字は区別されるので、例えばfeature.FULLNAMEとfeature.fullnameは異なる参照と見なされてしまう。

 このように、マップビュワーにて道路をクリックすると、テーブル中の全データを無秩序に一覧するのではなく、事前に指定した表示形式にて特定の情報だけを表示させるという機構を設ける場合も、こうしたテンプレートを組み込むだけで済むのだ。

まとめ

 本稿の解説は、Geoserverを用いたマップ表示機能のごく一部を紹介しただけに過ぎない。Geoserverの付属ドキュメントには、マップへのスタイル適用およびラベル配置に関する詳細だけでなく、衛星写真などのラスタデータの処理、表示したマップのダウンロード機能の実装、FeatureTypeをキャッシュすることによるパフォーマンス向上といった、本稿では触れることのできなかった高度な機能についても解説されている。

Justin Palkは、ミシガン大学にてコンピュータサイエンスの学士号を取得しており、ソフトウェア開発に2年間従事した後、ジャーナリストとして活動をしている。

Linux.com 原文(2008年9月24日)