OSM(OpenStreetMap)標準地図では、崖(natural=cliff)のレンダリングには小さなアイコン「 」を使う。このアイコンは中央に細い線があり、中央から下に向かって小さな三角「▼」が描かれている。
この小さな画像を曲線に沿って▼が上から下に向かうように描きならべると、下のようになる。 これが標準OSM地図における崖のレンダリングである。
これを C# で実現するには、曲線に沿って文字列を描画するのと同じ方法を使う。 曲線といっても、拡大してみれば無数の直線線分がつながったものである。
プログラムとしては、大きくは線分の数だけループして、 線分ではそこに並ぶアイコン(小さな画像データ)の数だけループする。
角度計算は線分ごとでよいが、アイコンの中心座標の計算はアイコン毎となる。 g.TranslateTransform(x1-dx/2, y1-dy/2) により、画像操作の中心をアイコンの中心とする。 次に、g.RotateTransform(deg)により、アイコンを水平方向に描画すれば、回転されるように設定しておく。
DrawImageメソッドの引数は、アイコンの中心ではなく、左上座標であるから、 g.DrawImage(img, -img.Width/2, -img.Height/2) とすることにより、線分の中心とアイコンの中心が一致する。
// iconをラインに沿って繰り返し描画する public void DrawIconMulti(Graphics g, Image img, TileToRender tile) { PointF[] points = GetPointArray(tile, 0, num_nodes); if (points == null || points.Length <= 1) return; float prv_x = points[0].X, prv_y = points[0].Y; for (int k = 1; k < points.Length; k++) { float x = points[k].X; float y = points[k].Y; float dist = (float)Distance(x, y, prv_x, prv_y); int num_icons = (int)((dist + 0.5f)/img.Width); float dx = (x - prv_x) / num_icons; float dy = (y - prv_y) / num_icons; float deg = (float)Degree(prv_x, prv_y, x, y); float x1 = x, y1 = y; for (int n = 0; n < num_icons; n++, x1 -= dx, y1 -= dy) { g.ResetTransform(); g.TranslateTransform(x1-dx/2, y1-dy/2); // 中心 g.RotateTransform(deg); g.DrawImage(img, -img.Width/2, -img.Height/2); } g.ResetTransform(); prv_x = x; prv_y = y; } }
線分間隔が短く、一つの線分にアイコンが描画できない場合、 近似的に複数の線分に一つのアイコンを割り当てる必要がある。
地図システムとしては、崖のレンダリングだけでなく、一般に、 レンダリング精度上必要とする以上にノード数が多いのはパフォーマンス上無駄であるから、 間引き等により、ノード数を減らした方がよい。
したがって、近似曲線を求めるプログラムは DrawIconMultiメソッドとは切り離し、 全レコードに適用する。