2012年12月22日土曜日

5mメッシュ標高データで地図を作成

メッシュ標高データを使って地図を作成します。
データは XML で、ある緯度経度のエリアを、縦横5mごとの格子に分割した標高データが格納されています。

南北と東西がいくつの格子からなっているかは、low要素と high要素から判別します。
サンプルでは、南北が 0から149まで、東西が0から224 までなので 225列×150行の合計33750個の格子が存在ます。
どの格子が標高何メートルなのかは、tupleList要素を見ます。 各格子の標高が改行区切りで格納さています。順番は、最初が1行目の1列目で、2、3列目とつづき、225列目までいったら、226個目が2行目の1列目です。

1つのXMLファイルで、東西が5m×225=1125mのエリアの地図が描けることになります。
各格子の標高が0mから50mなら色の濃淡をつけて、50m以上なら黒、マイナスなら水色にしています。

5mメッシュ標高データは、国土地理院の基盤地図情報のダウンロードページから入手できます。 (http://fgd.gsi.go.jp/download/)


ログイン後、基盤地図情報 数値標高モデル JPGIS (GML)形式
→ 5mメッシュ → 沖縄 → 3927 → 392715
を選択して、沖縄県糸満市周辺のデータをダウンロードします。
サンプルでは、ダウンロードした FG-GML-3927-15-DEM5B.zipを 解凍してできたファイル「FG-GML-3927-15-02-DEM5B-20110915.xml」を読み込んでいます。



Google Map でみた同じ場所


MainWindow.xaml

<Window x:Class="GisTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Height="380" Width="480">
    <Window.CommandBindings>
        <CommandBinding Command="Open" Executed="OpenCommandHandler"/>
    </Window.CommandBindings>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Menu Grid.Row="0">
            <MenuItem Command="Open" />
        </Menu>
        <Canvas Grid.Row="1" Name="canvas1" Margin="3">
            <Canvas.Resources>
                <Style TargetType="Rectangle">
                    <Setter Property="StrokeThickness" Value="0" />
                    <Setter Property="Width" Value="2" />
                    <Setter Property="Height" Value="2" />
                </Style>
            </Canvas.Resources>
        </Canvas>
    </Grid>
</Window>

MainWindow.xaml.cs

using Microsoft.Win32;
using System;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Xml;

namespace GisTest
{
    public partial class MainWindow Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void OpenCommandHandler(object sender, ExecutedRoutedEventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            if (ofd.ShowDialog() == true)
            {
                XmlDocument xdoc = new XmlDocument();
                xdoc.Load(ofd.FileName);

                XmlNamespaceManager xnm = new XmlNamespaceManager(xdoc.NameTable);
                xnm.AddNamespace("gml""http://www.opengis.net/gml/3.2");

                XmlElement dataXe = (XmlElement)xdoc.SelectSingleNode("//gml:tupleList", xnm);
                XmlElement lowXe = (XmlElement)xdoc.SelectSingleNode("//gml:low", xnm);
                XmlElement highXe = (XmlElement)xdoc.SelectSingleNode("//gml:high", xnm);

                string[] lowPoint = lowXe.InnerText.Split(' ');
                string[] highPoint = highXe.InnerText.Split(' ');
                int xSize = int.Parse(highPoint[0]) - int.Parse(lowPoint[0]) + 1;
                int ySize = int.Parse(highPoint[1]) - int.Parse(lowPoint[1]) + 1;
                string data = dataXe.InnerText;

                DrawMap(xSize, ySize, data);
            }
        }

        private void DrawMap(int xSize, int ySize, string data)
        {
            float[,] heights = new float[xSize, ySize];

            Regex regex = new Regex("[^,\\r\\n]+,[^,\\r\\n]+");
            MatchCollection mc = regex.Matches(data);
            int index = 0;
            foreach (Match in mc)
            {
                string[] unit = m.Value.Split(',');
                heights[index % xSize, index / xSize] = float.Parse(unit[1]);
                index++;
            }

            this.canvas1.Children.Clear();

            for (int x = 0; x < xSize; x++)
            {
                for (int y = 0; y < ySize; y++)
                {
                    Rectangle r = new Rectangle();
                    r.SetValue(Canvas.LeftProperty, (double)x * 2);
                    r.SetValue(Canvas.TopProperty, (double)y * 2);
                    double height = Math.Floor(heights[x, y] * 5);
                    Color fillColor;
                    if (height <= 0)
                    {
                        fillColor = Colors.AliceBlue;
                    }
                    else if (height > 255)
                    {
                        fillColor = Colors.Black;
                    }
                    else
                    {
                        byte colorValue = byte.Parse((255 - height).ToString());
                        fillColor = Color.FromRgb(colorValue, colorValue, colorValue);
                    }
                    r.Fill = new SolidColorBrush(fillColor);
                    this.canvas1.Children.Add(r);
                }
            }
        }
    }
}

0 件のコメント:

コメントを投稿