トップC# > 見栄えのいい線(色違いの二重線)を描画する

見栄えのいい線(色違いの二重線)を描画する

1.はじめに

標準OSMでは、テーマパークや動物園の境界線は下に示すように、ラインの垂直方向に gradation のかかった線(色違いの二重線)を引く。

できればこれと同等のことを C# でやってみたい。

2.プログラム

Mapnik版では次のようにしている。外側に濃くて細い線、内側に薄くて太い線を描く。 濃い、薄いは色ではなく透過率で実現している。

offsetの指定により、多角形の境界線より少し内側に線を引いている。

  <Rule>
    &min_zoom10;
    &max_zoom13;
    <Filter>([tourism] = 'theme_park' or [tourism] = 'zoo')
      and [way_area] >= 100000 and not [name] is null</Filter>
    <LineSymbolizer stroke="#660033" stroke-width="1" offset="-0.5" stroke-opacity="0.6"/>
    <LineSymbolizer stroke="#660033" stroke-width="4" offset="-2" stroke-opacity="0.3"/>
  </Rule>

C# では多重線を引く機能がある[1]。順に描画区間、空白区間、描画区間、空白区間・・・を配列で指定する。

  pen.CompoundArray = new float[] {0f, 0.33f, 0.67f, 1.0f};
  e.Graphics.DrawLine(pen, point1, point2);

試行錯誤の結果、C# では次のようにした。inner は alphaを下げ、普通に線を描いている。 outer は同じ太さであるが、実質外側の25%だけを描画している。alpha は上げて濃く見える ようにしている。折れ線の継ぎ目が少し目立つので、LineCap.Roundも試したが、使わない方が 良さそうだった。

        foreach (OSM osm in osms) {
            if (osm.type != 2) continue;
            if (osm.Tourism == ValCode.theme_park || osm.Tourism == ValCode.zoo) {
                Pen penOuter = new Pen(Color.FromArgb(150, 0xcc, 0x00, 0x66), 4.0f);
                Pen penInner = new Pen(Color.FromArgb( 75, 0xcc, 0x00, 0x66), 4.0f);
                penOuter.CompoundArray = new float[] {0, 0.01f, 0.75f, 1.0f};
                //penInner.StartCap = LineCap.Round;
                DrawLine(g, penOuter, zoom, X, Y, osm.points);
                DrawLine(g, penInner, zoom, X, Y, osm.points);
                DrawString(g, zoom,X,Y, osm.center, "Meiryo UI", 
                            FontStyle.Bold, brThemePark, 14, 0, osm.name, penStdHalo);
            }
        }

描画結果を下に示す。まだ、これから描画するものがたくさんある[2021.4.25]。

Mapnikの場合、フリー描画ソフトを使っているはずだが、その方法で交点を求めているか、 あるいはもう少し効率の良い方法があるのかも知れない。

頂点座標を単純に拡大または縮小する方法ではうまく行かない。 例えば、頂点座標が (0, 0) では移動が起きない。絶対値が大きいほど大きく移動する。線分の平行移動とはならない。

自前のプログラムで、 多角形の少し内側とか外側に境界線を引くのは面倒である。 線分ごとに平行線を描くのがスタート点となるが、線分同士が交差したり、しなかったりする。 平行線分同士の交点を算出して、そこを求める多角形の交点とすればよい。

頂点が重なっていた場合、一つのものとして扱わないと、線分にはならない。

平行な線分同士では交点は存在しないが、元々の線分は端点でつながっていたものであるから、 それぞれを平行移動した線分を無限の長さの直線とすれば、必ず交点は存在する。

A.リファレンス

[1] 直線を描画する