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 の実体を探すと、次のようになります。

  1. http://trac.osgeo.org/postgis/browser/trunk/postgis/postgis.sql.in.c で、ST_AsSVG の定義を調べると、LWGEOM_asSVG が呼ばれていることが分かる。
  2. http://trac.osgeo.org/postgis/browser/trunk/postgis/lwgeom-export.c で、LWGEOM_asSVG の定義を調べると、lwgeom_to_svg が呼ばれていることが分かる。
  3. http://trac.osgeo.org/postgis/browser/trunk/liblwgeom/lwout_svg.c で、lwgeom_to_svg が定義されており、幾何データの型ごとに switch 文で分岐していて、Polygon については、assvg_polygon が呼ばれていることが分かる。
  4. 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);
}

この関数がやっていることは意外と単純で、

  1. ポリゴンを構成するすべてのリングについて、「M (座標列) Z」(座標列を差分で記述する場合には Z を z とする)を作成し、それを空白でつなぐ

だけです。SVG の場合、それだけで穴あきポリゴンが作成されるようです(要確認ですので、あとで確認します)。

*1:最近は。かつては lwpostgis.sql