プログラムは、「5mメッシュ標高データで3D地図」とほとんど同じです。
高さの比率 heightScale の値と、PerspectiveCamera の設定だけ変更しています。
高さの比率
double heightScale = 20;
PerspectiveCameraの設定
<PerspectiveCamera
FarPlaneDistance="1000"
LookDirection="0,0,-1"
UpDirection="0,1,0"
NearPlaneDistance="2"
Position="562,-375,700"
FieldOfView="90" />
画像の場所は、「10mメッシュ標高データで地図を作成」のサンプルと同じで、沖縄県の辺野古周辺です。
FG-GML-3928-60-dem10b-20090201.xml
拡大図
WPF Notes
C#、WPFのメモ
2013年1月12日土曜日
5m メッシュ標高データで 3D地図
XMLデータのパースは、「5mメッシュ標高データで地図を作成」と同じです。
1つのメッシュをそれぞれ空間座標の1つの点としてみます。
ある点(x, y, z1)を左上とした4つの点からなる地形は、2つの三角形で構成します。
(x ,y ,z1)、(x + 1 ,y ,z2)、(x + 1 ,y + 1 ,z3) を頂点とする三角形と、(x ,y ,z1)、(x ,y + 1 ,z4)、(x + 1 ,y + 1 ,z3) を頂点とする三角形 です。
すべての点について、これらの三角形を、MeshGeometry3D の Positions に追加して、全体の地形を作っています。
「5mメッシュ標高データで地図を作成」のサンプルと同じ場所を3Dで表示してみました。
FG-GML-3927-15-02-DEM5B-20110915.xml
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media.Media3D;
using System.Xml;
namespace GisTest3
{
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 m in mc)
{
string[] unit = m.Value.Split(',');
heights[index % xSize, index / xSize] = (float.Parse(unit[1]) < 0) ? 0 : float.Parse(unit[1]);
index++;
}
MeshGeometry3D meshGeometry3D = (MeshGeometry3D)((GeometryModel3D)((Model3DGroup)((ModelVisual3D)this.myViewport.Children[0]).Content).Children[1]).Geometry;
meshGeometry3D.Positions.Clear();
double heightScale = 3;
for (int x = 0; x < xSize; x++)
{
for (int y = 0; y < ySize; y++)
{
if (x < xSize - 1 && y < ySize - 1)
{
Point3D p11 = new Point3D(x, -1 * y, heights[x, y] / heightScale);
Point3D p12 = new Point3D(x + 1, -1 * y, heights[x + 1, y] / heightScale);
Point3D p13 = new Point3D(x + 1, -1 * (y + 1), heights[x + 1, y + 1] / heightScale);
Point3D p21 = new Point3D(x, -1 * y, heights[x, y] / heightScale);
Point3D p22 = new Point3D(x + 1, -1 * (y + 1), heights[x + 1, y + 1] / heightScale);
Point3D p23 = new Point3D(x, -1 * (y + 1), heights[x, y + 1] / heightScale);
meshGeometry3D.Positions.Add(p13);
meshGeometry3D.Positions.Add(p12);
meshGeometry3D.Positions.Add(p11);
meshGeometry3D.Positions.Add(p23);
meshGeometry3D.Positions.Add(p22);
meshGeometry3D.Positions.Add(p21);
}
}
}
}
}
}
1つのメッシュをそれぞれ空間座標の1つの点としてみます。
ある点(x, y, z1)を左上とした4つの点からなる地形は、2つの三角形で構成します。
(x ,y ,z1)、(x + 1 ,y ,z2)、(x + 1 ,y + 1 ,z3) を頂点とする三角形と、(x ,y ,z1)、(x ,y + 1 ,z4)、(x + 1 ,y + 1 ,z3) を頂点とする三角形 です。
すべての点について、これらの三角形を、MeshGeometry3D の Positions に追加して、全体の地形を作っています。
「5mメッシュ標高データで地図を作成」のサンプルと同じ場所を3Dで表示してみました。
FG-GML-3927-15-02-DEM5B-20110915.xml
MainWindow.xaml
<Window x:Class="GisTest3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="350" Width="525">
<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>
<Viewport3D Grid.Row="1" Name="myViewport">
<Viewport3D.Camera>
<PerspectiveCamera
FarPlaneDistance="200"
LookDirection="0,0,-1"
UpDirection="0,1,0"
NearPlaneDistance="2"
Position="112,-75,150"
FieldOfView="90" />
</Viewport3D.Camera>
<Viewport3D.Children>
<ModelVisual3D>
<ModelVisual3D.Content>
<Model3DGroup>
<Model3DGroup.Children>
<DirectionalLight Color="#FFFFFFFF" Direction="5,0,-4" />
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D />
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<SolidColorBrush Color="White" />
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
</GeometryModel3D>
</Model3DGroup.Children>
</Model3DGroup>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D.Children>
</Viewport3D>
</Grid>
</Window>
MainWindow.xaml.cs
using Microsoft.Win32;using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media.Media3D;
using System.Xml;
namespace GisTest3
{
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 m in mc)
{
string[] unit = m.Value.Split(',');
heights[index % xSize, index / xSize] = (float.Parse(unit[1]) < 0) ? 0 : float.Parse(unit[1]);
index++;
}
MeshGeometry3D meshGeometry3D = (MeshGeometry3D)((GeometryModel3D)((Model3DGroup)((ModelVisual3D)this.myViewport.Children[0]).Content).Children[1]).Geometry;
meshGeometry3D.Positions.Clear();
double heightScale = 3;
for (int x = 0; x < xSize; x++)
{
for (int y = 0; y < ySize; y++)
{
if (x < xSize - 1 && y < ySize - 1)
{
Point3D p11 = new Point3D(x, -1 * y, heights[x, y] / heightScale);
Point3D p12 = new Point3D(x + 1, -1 * y, heights[x + 1, y] / heightScale);
Point3D p13 = new Point3D(x + 1, -1 * (y + 1), heights[x + 1, y + 1] / heightScale);
Point3D p21 = new Point3D(x, -1 * y, heights[x, y] / heightScale);
Point3D p22 = new Point3D(x + 1, -1 * (y + 1), heights[x + 1, y + 1] / heightScale);
Point3D p23 = new Point3D(x, -1 * (y + 1), heights[x, y + 1] / heightScale);
meshGeometry3D.Positions.Add(p13);
meshGeometry3D.Positions.Add(p12);
meshGeometry3D.Positions.Add(p11);
meshGeometry3D.Positions.Add(p23);
meshGeometry3D.Positions.Add(p22);
meshGeometry3D.Positions.Add(p21);
}
}
}
}
}
}
2012年12月27日木曜日
string.Length は文字数ではなく char の数
string.Length は char の数 を取得します。
UTF-16 では、1文字を 2バイトまたは4バイトであらわすので、文字列中に 1文字が 4バイトの文字がある場合、Lengthは 文字数になりません。
このような文字列の文字数を取得するには、StringInfo.LengthInTextElements を使います。
また、部分文字列の取得も、「n文字目からm文字・・ 」などで指定する場合は、string.Substring ではなく、StringInfo.SubstringByTextElements を使います。
サンプルプログラムは、入力した文字列の 文字数(StringInfo.LengthInTextElements) と char数(string.Substring) と、各文字の文字コード(UTF-16)を表示します。
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="350" Width="425">
<DockPanel LastChildFill="True">
<TextBox Name="textBox1" DockPanel.Dock="Top"/>
<Button Click="Button_Click_1" DockPanel.Dock="Top">更新</Button>
<TextBlock Name="textBlock1" DockPanel.Dock="Top"/>
</DockPanel>
</Window>
using System.Globalization;
using System.Windows;
namespace StringInfoTest
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
string text = this.textBox1.Text;
StringInfo stringInfo = new StringInfo(text);
string charCode = "";
for (int i = 0; i < stringInfo.LengthInTextElements; i++)
{
string token = stringInfo.SubstringByTextElements(i, 1);
charCode += "\n" + token + " : ";
for (int j = 0; j < token.Length; j++)
{
charCode += " " + ((int)token[j]).ToString("X4");
}
}
this.textBlock1.Text = "StringInfo.LengthInTextElements = " + stringInfo.LengthInTextElements +
"\nstring.Length = " + text.Length +
"\n" + charCode;
}
}
}
UTF-16 では、1文字を 2バイトまたは4バイトであらわすので、文字列中に 1文字が 4バイトの文字がある場合、Lengthは 文字数になりません。
このような文字列の文字数を取得するには、StringInfo.LengthInTextElements を使います。
また、部分文字列の取得も、「n文字目からm文字・・ 」などで指定する場合は、string.Substring ではなく、StringInfo.SubstringByTextElements を使います。
サンプルプログラムは、入力した文字列の 文字数(StringInfo.LengthInTextElements) と char数(string.Substring) と、各文字の文字コード(UTF-16)を表示します。
MainWindow.xaml
<Window x:Class="StringInfoTest.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="350" Width="425">
<DockPanel LastChildFill="True">
<TextBox Name="textBox1" DockPanel.Dock="Top"/>
<Button Click="Button_Click_1" DockPanel.Dock="Top">更新</Button>
<TextBlock Name="textBlock1" DockPanel.Dock="Top"/>
</DockPanel>
</Window>
MainWindow.xaml.cs
using System.Windows;
namespace StringInfoTest
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
string text = this.textBox1.Text;
StringInfo stringInfo = new StringInfo(text);
string charCode = "";
for (int i = 0; i < stringInfo.LengthInTextElements; i++)
{
string token = stringInfo.SubstringByTextElements(i, 1);
charCode += "\n" + token + " : ";
for (int j = 0; j < token.Length; j++)
{
charCode += " " + ((int)token[j]).ToString("X4");
}
}
this.textBlock1.Text = "StringInfo.LengthInTextElements = " + stringInfo.LengthInTextElements +
"\nstring.Length = " + text.Length +
"\n" + charCode;
}
}
}
2012年12月25日火曜日
10mメッシュ標高データで地図を作成
「5mメッシュ標高データで地図を作成」では、1メッシュごとにRectangle オブジェクトを生成していましたが、ここではビットマップ画像を作成します。
1メッシュが1ピクセルになります。
標高は512mまでを256段階のグレースケールで表現し、512m以上は一律黒にします。
10mメッシュ標高データのXMLをみると、1125列×750行のメッシュになっているので、1125×750ピクセルの画像が生成されることになります。
サンプルは、沖縄県の辺野古あたりです。
XMLファイルは、「FG-GML-3928-60-dem10b-20090201.xml」です。
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="250" Width="325">
<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>
<ScrollViewer Grid.Row="1" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible">
<Canvas Name="canvas1" Margin="2"/>
</ScrollViewer>
</Grid>
</Window>
using System;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Xml;
namespace GisTest2
{
public partial class MainWindow : Window
{
private static Color[] myColors = new Color[256];
static MainWindow()
{
byte i = 0;
while (true)
{
myColors[i] = Color.FromRgb(i, i, i);
if (i == 255)
{
break;
}
i++;
}
}
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;
this.canvas1.Width = xSize;
this.canvas1.Height = ySize;
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 m in mc)
{
string[] unit = m.Value.Split(',');
heights[index % xSize, index / xSize] = float.Parse(unit[1]);
index++;
}
this.canvas1.Children.Clear();
byte[] pixcels = new byte[xSize * ySize * 4];
for (int y = 0; y < ySize; y++)
{
for (int x = 0; x < xSize; x++)
{
double height = Math.Floor(heights[x, y] / 2.0);
Color fillColor;
if (height <= 0)
{
fillColor = Colors.LightSeaGreen;
}
else if (height > 255)
{
fillColor = Colors.Black;
}
else
{
fillColor = myColors[(byte)(255 - height)];
}
int pixcelIndex = xSize * 4 * y + x * 4;
pixcels[pixcelIndex] = fillColor.B;
pixcels[pixcelIndex + 1] = fillColor.G;
pixcels[pixcelIndex + 2] = fillColor.R;
pixcels[pixcelIndex + 3] = 0;
}
}
Int32Rect rect = new Int32Rect(0, 0, xSize, ySize);
WriteableBitmap bitmapImage = new WriteableBitmap(xSize, ySize, 96, 96, PixelFormats.Bgr32, null);
bitmapImage.WritePixels(rect, pixcels, xSize * 4, 0);
Rectangle rectangle = new Rectangle();
rectangle.Width = xSize;
rectangle.Height = ySize;
rectangle.Fill = new ImageBrush(bitmapImage);
this.canvas1.Children.Add(rectangle);
}
}
}
1メッシュが1ピクセルになります。
標高は512mまでを256段階のグレースケールで表現し、512m以上は一律黒にします。
10mメッシュ標高データのXMLをみると、1125列×750行のメッシュになっているので、1125×750ピクセルの画像が生成されることになります。
サンプルは、沖縄県の辺野古あたりです。
XMLファイルは、「FG-GML-3928-60-dem10b-20090201.xml」です。
MainWindow.xaml
<Window x:Class="GisTest2.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="250" Width="325">
<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>
<ScrollViewer Grid.Row="1" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible">
<Canvas Name="canvas1" Margin="2"/>
</ScrollViewer>
</Grid>
</Window>
MainWindow.xaml.cs
using Microsoft.Win32;using System;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Xml;
namespace GisTest2
{
public partial class MainWindow : Window
{
private static Color[] myColors = new Color[256];
static MainWindow()
{
byte i = 0;
while (true)
{
myColors[i] = Color.FromRgb(i, i, i);
if (i == 255)
{
break;
}
i++;
}
}
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;
this.canvas1.Width = xSize;
this.canvas1.Height = ySize;
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 m in mc)
{
string[] unit = m.Value.Split(',');
heights[index % xSize, index / xSize] = float.Parse(unit[1]);
index++;
}
this.canvas1.Children.Clear();
byte[] pixcels = new byte[xSize * ySize * 4];
for (int y = 0; y < ySize; y++)
{
for (int x = 0; x < xSize; x++)
{
double height = Math.Floor(heights[x, y] / 2.0);
Color fillColor;
if (height <= 0)
{
fillColor = Colors.LightSeaGreen;
}
else if (height > 255)
{
fillColor = Colors.Black;
}
else
{
fillColor = myColors[(byte)(255 - height)];
}
int pixcelIndex = xSize * 4 * y + x * 4;
pixcels[pixcelIndex] = fillColor.B;
pixcels[pixcelIndex + 1] = fillColor.G;
pixcels[pixcelIndex + 2] = fillColor.R;
pixcels[pixcelIndex + 3] = 0;
}
}
Int32Rect rect = new Int32Rect(0, 0, xSize, ySize);
WriteableBitmap bitmapImage = new WriteableBitmap(xSize, ySize, 96, 96, PixelFormats.Bgr32, null);
bitmapImage.WritePixels(rect, pixcels, xSize * 4, 0);
Rectangle rectangle = new Rectangle();
rectangle.Width = xSize;
rectangle.Height = ySize;
rectangle.Fill = new ImageBrush(bitmapImage);
this.canvas1.Children.Add(rectangle);
}
}
}
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 でみた同じ場所
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>
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 m 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);
}
}
}
}
}
データは 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 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 m 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);
}
}
}
}
}
登録:
投稿 (Atom)