マップファイル(Mapfile)Label ENCODING

担当業務から離れてしまい、MapServerをいじる機会がほぼなくなってしまい、ここの更新も止まっています。

離れる直前に悩んだいたのが、標記の件です。

結論としては、Windows環境下で、Shift-JIS形式で文字を扱うとき、
ENCODING="CP932"
を利用すると、幸せであるということです。
MapServerの国際化の中で、先輩方のご尽力で日本語環境も扱えるようになったのですが、このときのドキュメント類を探すことができませんでした。
下記URLで表示されるページが唯一の手がかりと思っていましたが、現在は、関連する情報が表示されません。
http://www.foss4g.org/FOSS4G/MAPSERVER/mpsnf-i18n-en.html

Windows環境下の利用において、ラベルで日本語表示をする時は、
http://mapserver.org/mapfile/label.html
等を参考にすると、

LABEL
...
ENCODING "SJIS"
...
END

のように記述し、SJIS,UTF-8,EUCなどの指定をするのが一般的です。

ただ、Windowsの場合、俗にいうローマ数字の2バイト文字や(株)などの、いわゆる機種依存文字が上記の指定では、UTF-8でのみ表示できます。
SJISで指定すると対応するコードがないと判断され文字化けしてしまいます。

UTF-8で統一すれば?というご指摘がもっともですが、なかなかそうも行かない状況が
でてきます。
Windows上では、Shapefileのdbfや、MapInfoのDATなどは、Shift-JISで記述されています。
むりやりdbfをUTF-8化することも可能ですが、データの再利用性など弊害が多くなります。

データに関しては、Shift-JISのものはShift-JISのまま、UTF-8はUTF-8のままとして、ラベルだけを文字化けなく表示させたい。
ただ、日本人は、○に1や全角のローマ数字などの機種依存文字ををデータの中の値として利用することに、抵抗がなく、いちいちこれを修正するのはたいへんです。

ソースを深く追求していないのですが、MapServer上では、文字のコード変換をiconvライブラリが変換していると思われます。
iconvを使って、UTF-8をSJISにした場合、機種依存文字があると、文字化けを起こすことがあります。iconvのコードページ拡張などがされているものが、リリースされていたりなどからもこの問題が認識されていることがわかります。

4ヶ月も悩んだあげく、だめもとで、ENCODING に指定できる、SJIS,UTF-8,EUC のところに、CP932 と入れてみたら、いままでの悩みがいっぺんに解消されました。

この機種依存文字は、NECによる拡張やIBMの拡張があり、内容については、
下記ページ等を参照していただきたいのですが、同じ文字でも2つコードがあったりと、
日本語の文字に関しては多くの議論がされているようです。
http://ja.wikipedia.org/wiki/Microsoftコードページ932

Windows環境下での利用も増えつつあるよう思えるので、日本語をラベル表示することがある方は、是非試してみてください。
bugna | MapServer | 10:09 | comments(0) | trackbacks(0) | - | - |

SQLiteで空間検索

、といっても、SpatiaLiteのことではないです。。。

SQLiteは、たくぼさんの記事にあるように、MapServerでは、OGR経由で表示することができる。けれども、空間インデックスや空間検索のようなものをもっていないので、道路ネットワークのノードみたいな、たくさんのポイントを、layerObj.queryByPointで検索をかけると、みつけるのにとっても時間がかかる。常套手段としては、Shapefileに変換して、MS4Wに含まれるshptree(C:¥ms4w¥tools¥mapserv¥shptree)で空間インデックスを作ると速くなる。座標系変換も時間がかかるので、これもあらかじめあわせておくとなおよい。

ただ今回は、SQLite上では動的にポイントデータをつくったりするので、SQLiteのままで使いたい。

そこでググってみると、とってもいい回答をしているスレッドを見つけた。

Re: [sqlite] Spatial searches

対象はポイントデータなのでなおよい。
・緯度経度やXYのカラムを作っておいて、インデックスを作成
create table pts (
id integer primary key,
lat real,
lng real,
data text
);

create index lat_idx on pts(lat);
create index lng_idx on pts(lng);

・select文で、between を使って絞り込む
select * from pts where id in
(
select id from pts where lat between :min_lat and :max_lat
intersect
select id from pts where lng between :min_lng and :max_lng
);


これだけなのですが、SQLはNewbieな私にとっては、この解決策はとってもカッコよく思いました。SQL の中に、intersect というのがあるのですね。といっても、空間を対象にした演算子ではなく、2つのselect文の交差を取るということのようです(参照

layerObj.queryByPoint の引数の最後には、buffer というのがあり、与えられた点の周辺どのくらいの範囲を検索するかというパラメータが与えられています。
public int queryByPoint(
mapObj map,
pointObj point,
int mode,
double buffer
);

Public Function queryByPoint(ByVal map As mapObj, ByVal point As pointObj, ByVal mode As Integer, ByVal buffer As Double) As Integer


上記のselect文にある、:min_lat、:max_lat、min_lng and :max_lng の部分に、buffer 相当の値を入れれば、SQLite上で、layerObj.queryByPointとほぼ同じ機能を持つことになります。

buffer 相当の計算は、MapServerのマップ上で、たとえば5ピクセル相当の距離を出して与えれるようにすると、ちょうどよいです。

Dim _buffer As Double
_buffer = 5 * (map.extent.maxx - map.extent.minx) /map.width


さて、実際にマップ上で、OGR経由で表示させたSQLiteに対しては次のようにして、検索をかけるようにしました。
・マップ上のクリック点の取得→マウスのX,Yの値を取得
・Yaskeyさんのサイトにある、Pix2Geoを参考にして、緯度経度に変換。
・buffer を計算(前掲)
・上記select文を使って、毎回 Viewを作成

MapScriptが、layerObj.queryByPoint をテレんこテレんこと実行するよりか、コストがかかりそうな処理であろうとも、クリックされるたびに、Viewを消して作り直す処理のほうが、はるかに高速です。それに、SQLiteは、ローカルで自分だけが使っているし、そもそも高速だし^^;

(追記)
実際のポイントの点数として、7000点のものと、10万点、30万点のものでためしてみました。7000点と10万点はクリックした瞬間に結果を得ることができました。さすがに30万点は10秒くらい検索にかかりました。30万点でも、7000点、10万点と同じく、クリックした瞬間に結果を得ることができました(前掲訂正)。ポリゴンやラインでもMBR(最小包囲矩形)のmin,max を使うことで応用が利きそうです。

MapServerは、SQLiteのViewテーブルからでも地図にプロットすることができます。最後にマップファイル例を挙げておきます。

 Dim georefpoint As System.Drawing.PointF
 georefpoint = Pix2Geo(_map, clientPoint)
 '検索時のバッファーを現在の縮尺における5ピクセルあたりの長さにする
 Dim _dblBuffer As Double
 _dblBuffer = 5 * (_map.extent.maxx - _map.extent.minx) / _map.width
 
 strNWPt(0) = roadnw.CreateRoadNWView(georefpoint, _dblBuffer)


Public Function CreateRoadNWView(ByVal geopoint As PointF, ByVal buffer As Double) As String
'Dim conn As New SQLiteConnection("Version=3;Data Source=..¥map¥23.db;New=True;Compress=True;")

'データベースを SQLiteConnection parameters 通りにオープン
conn.Open()

'SQLコマンド用のクラス
'Dim cmd As New SQLiteCommand

'SQLコマンド用のクラスに開いたデータベースの情報を与える
cmd = conn.CreateCommand

'トランザクションクラス
'Dim Transact As SQLiteTransaction

'トランザクションスタート
Transact = conn.BeginTransaction

'SQLを登録
cmd.CommandText = "DROP view IF EXISTS test_v"

'SQLを実行
cmd.ExecuteNonQuery()

'SQLを登録
cmd.CommandText = _
"create view test_v as select * from nodenwSQ where OGC_FID in " & _
"( " & _
"select OGC_FID from nodenwSQ where x between " & geopoint.X - buffer & " and " & geopoint.X + buffer & _
" intersect " & _
"select OGC_FID from nodenwSQ where y between " & geopoint.Y - buffer & " and " & geopoint.Y + buffer & ")"

'Debug.WriteLine(cmd.CommandText)

'SQLを実行
cmd.ExecuteNonQuery()

'SQLを登録
cmd.CommandText = "select * from test_v"

'SQLのリーダークラス
Dim Rdr As SQLiteDataReader

'SQLを実行し、リーダーに格納
Rdr = cmd.ExecuteReader

Dim strTempValue As Integer

'Try
If Rdr.HasRows Then
Rdr.Read()
strTempValue = Rdr.GetInt32(2).ToString
Rdr.Close()
conn.Close()
Return Val(strTempValue)
Else
Rdr.Close()
'データをコミット
'Transact.Commit()
conn.Close()
Return 0
End If


Rdr.Close()

'データをコミット
Transact.Commit()

conn.Close()

Return strTempValue

End Function


■マップファイル SQLite Viewを使った表示
LAYER
CONNECTION "23.db,test_v"
CONNECTIONTYPE OGR
LABELCACHE OFF
NAME "SQLite_v"
POSTLABELCACHE TRUE
PROJECTION
"init=epsg:4612"
END
STATUS OFF
TEMPLATE "template.html"
TYPE POINT
UNITS METERS
CLASS
NAME "SQLite_v"
STYLE
ANGLE 360
COLOR 128 0 128
OPACITY 100
OUTLINECOLOR 255 128 128
SIZE 5
SYMBOL "circle"
WIDTH 2
END
END
END
bugna | SQLite | 09:29 | comments(0) | trackbacks(0) | - | - |

ArcGISの横暴さがイヤ

ArcGISは、システムの中でGDALやPythonを使っている。ファイル変換や、開発環境などに利用しているようである。
これが自分のシステムの中だけで動いているなら何の問題もない。
実行時に、自分たちで利用したいものがあるフォルダへ、パスをきってから動くなどするのが、自分の感覚からいうと普通である。

しかし、ArcGISは9.2から、gdal14.dllやpython.exe を、
C:¥Program Files¥ArcGIS¥Bin

においてあり、しかも、グローバルな環境変数PATHの先頭にどうどうと、このフォルダへのパスをきっている。

この横暴さは、まことに遺憾。やめてくれ。

このため、コマンドラインから、python と打っても、python インタプリタは起動しないし、どうやってコンパイルのしたのか得たいも知れない、gdal14.dll を最初に見つけてしまうため、MapScriptやGDAL/OGR のプログラムが、意味もわからずアベンドしてしまう。

ESRIなどのプロプライエタリィな製品がようやくオープンソースへとすりよりはじめているが、横浜スローライフさんの記事にあるとおり、チグハグ感はまだ残る。

ソフトウェアがそれを現しておらず自分たちのプログラムを動かすために、このようなしているのだろうし、他でコンパイルしたDLLを参照してもうまく動かなかったからだろう。

ユーザーが、オープンソースのライブラリを使うとき、どんなバージョンをどのように利用するかには、たくさん調べてうまくいく方法を模索している。

自分たちのエゴのために、オープンソースを利用する流儀をわきまえず、このようなことをするんじゃない!
bugna | Python | 09:52 | comments(0) | trackbacks(0) | - | - |

Ubuntu(8.04 Hardy Haron)でPython環境構築

Ubuntu上での環境構築は、Windows、Mac OS X に比べてとても簡単である。
Synapticパッケージマネージャですべて導入できる。
依存するパッケージの導入もしてくれるので、次のものを指定するのが一番楽かも。

・spe
・python-gdal
・python-mapscript
・python-qt4
・qt4-designer

・今回は、GeoTiff を読み込ませようと思い、以下からGeoTiffのデータをダウンロードしました。このGeoTiffは、ヘッダの部分に座標系が埋め込まれているはずです。これを表示させてみましょう。

 ■MapTools Download: /dl/geotiff/samples/other
 http://dl.maptools.org/dl/geotiff/samples/other/
 この中の、erdas_spnad83.tif をダウンロードします。 

・SPEを起動して、

import mapscript
import gdal,gdalconst,ogr,osr

aa = mapscript.mapObj("")

print aa.name

gdal.AllRegister
dataset = gdal.Open('/Users/bugna/Projects/Python/erdas_spnad83.tif', gdal.GA_ReadOnly)


print 'Driver: ', dataset.GetDriver().ShortName,'/', dataset.GetDriver().LongName
print dataset.GetProjection()


などとして実行すると、

MS
Driver: GTiff / GeoTIFF
PROJCS["NAD83 / Georgia East",GEOGCS["NAD83",DATUM["North_American_Datum_1983",SPHEROID["GRS 1980",6378137,298.2572221010002,AUTHORITY["EPSG","7019"]],AUTHORITY["EPSG","6269"]],PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433],AUTHORITY["EPSG","4269"]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",30],PARAMETER["central_meridian",-82.16666666666667],PARAMETER["scale_factor",0.9999],PARAMETER["false_easting",656166.6666666666],PARAMETER["false_northing",0],UNIT["US survey foot",0.3048006096012192,AUTHORITY["EPSG","9003"]],AUTHORITY["EPSG","26966"]]

のような結果を得ることができます。

※GDAL のバージョンが、1.4 なので、Namespace osgeo を『つけ
ない』。import 行に注意。

bugna | Python | 07:49 | comments(0) | trackbacks(0) | - | - |

VBユーザーのためのGDAL/OGR

VBユーザーのためのGDAL/OGRなどというのを書き始めました。

いまになって、オープンソースソフトウェアになんでみんなソースを提供するのか?どういうからくりでお金が動いているのか?などという基本的なお勉強のために、Eric S. Raymond (エリック.S.レイモンド)のオープンソースを語る上で、有名な3部作がまとめて読める、『オープンソースワールド』を読んだ。これに絡んで、山形浩生氏の情報収集のために、ネット上をウロウロしていたら、こんな文章にぶちあたった。

プロジェクト杉田玄白(蘊蓄links)
良く言えばコミュニティに何でもいいから貢献したいという強い思い、悪く言えば翻訳という横道から Linux コミュニティに割り込んでいこうという狡猾さが僕の中にあったのだ。


、、、自分のことだ、、!! 赤面!

まぁいいや。それでも誰かの役には立つかもしれないから。


最初に、GDAL API Tutorialの意訳版を作った。サンプルコードもあり、GDAL/OGRの設計思想なようなものもかいま見れてとてもいい参考資料だと思ったからであるが、当然、VB(.NET)に関しての情報はないので、それも付け加えちゃいました。
それと、この記事で、Pythonのサンプルコードが、VBに似ていて読みやすかったので、Pythonに取り組もうと思ったきっかけになった記事でもあります。
bugna | VB.NET | 00:27 | comments(0) | trackbacks(0) | - | - |
1/9PAGES | >> |

08
--
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
--
>>
<<
--