ST_AsSVG も魔法ではない。(ST_AsSVG がポリゴンに対してやっていること)
PostGIS に含まれている便利な関数 ST_AsSVG ですが、魔法ではないので特別なことはしていません。穴あきポリゴンに対する ST_AsSVG の動きを追ってみます。
ST_AsSVG の実体を探す。
PostGIS の関数は、postgis.sql *1により定義されます。このファイルは、 http://trac.osgeo.org/postgis/browser/trunk/postgis/postgis.sql.in.c でいつでも閲覧できます。このファイルからはじめて、ST_AsSVG の実体を探すと、次のようになります。
- http://trac.osgeo.org/postgis/browser/trunk/postgis/postgis.sql.in.c で、ST_AsSVG の定義を調べると、LWGEOM_asSVG が呼ばれていることが分かる。
- http://trac.osgeo.org/postgis/browser/trunk/postgis/lwgeom-export.c で、LWGEOM_asSVG の定義を調べると、lwgeom_to_svg が呼ばれていることが分かる。
- http://trac.osgeo.org/postgis/browser/trunk/liblwgeom/lwout_svg.c で、lwgeom_to_svg が定義されており、幾何データの型ごとに switch 文で分岐していて、Polygon については、assvg_polygon が呼ばれていることが分かる。
- assvg_polygon の関連関数は、同じく http://trac.osgeo.org/postgis/browser/trunk/liblwgeom/lwout_svg.c に書かれているが、特に本質的な文字列処理を行っているのは、assvg_polygon_buf である。
assvg_polygon_buf がやっていること
static size_t assvg_polygon_buf(LWPOLY *poly, char * output, int relative, int precision) { int i; char *ptr=output; for (i=0; i<poly->nrings; i++) { if (i) ptr += sprintf(ptr, " "); /* Space beetween each ring */ ptr += sprintf(ptr, "M "); /* Start path with SVG MoveTo */ if (relative) { ptr += pointArray_svg_rel(poly->rings[i], ptr, 0, precision); ptr += sprintf(ptr, " z"); /* SVG closepath */ } else { ptr += pointArray_svg_abs(poly->rings[i], ptr, 0, precision); ptr += sprintf(ptr, " Z"); /* SVG closepath */ } } return (ptr-output); }
この関数がやっていることは意外と単純で、
- ポリゴンを構成するすべてのリングについて、「M (座標列) Z」(座標列を差分で記述する場合には Z を z とする)を作成し、それを空白でつなぐ
だけです。SVG の場合、それだけで穴あきポリゴンが作成されるようです(要確認ですので、あとで確認します)。