DotSpatial

Innen: GIS Wiki

A DotSpatial egy nyílt forráskódú térinformatikai programkönyvtár, amely különböző funkcionalitásokat biztosít téradat kezelés, betöltés és mentés, valamint elemzési feladatokra. A programkönyvtár C#-ban íródott és a .NET 4.0 keretrendszeren alapszik. Elsősorban asztali alkalmazások elkészítését segíti elő, amely a Windows Forms platformra épülnek. A programcsomag GNU LGPL licenc alatt használható.



Története

A könyvtár létrehozását az Idaho állami egyetemen (Idaho State University) fejlesztett MapWindow alkalmazás ihlette. Kezdetben csak a saját belső fejlesztésüket szerették volna megkönnyíteni különféle központi funkciók kiszervezésével, idővel azonban a felhalmozott szolgáltatások száma elérte azt a méretet, hogy a fejlesztők úgy érezték, érdemes kiadni a nagyközönség számára is. Sajnos a folyamatosan rétegződő, és központi koncepció nélküli fejlesztés rányomta a bélyegét a kódbázisra. Ennek megfelelően modulonként, vagy akár azokon belül is erősen eltérő megközelítéseket láthatunk a forráskódban.

Szolgáltatások

  • Térinformatikai adatok megjelenítése .Net Windows Form, vagy Web alkalmazásokban
  • Shapefájlok, rácshálók valamint raszter felvételek olvasása.
  • Menet közbeni projektálás
  • Tudományos analízis
  • GPS adatok olvasása

Kik használják?

Használat

Telepítést nem igényel, ha használni szeretnénk, akkor két lehetőségünk közül választhatunk.

  • Letölthetjük azt össze modult egyben a http://dotspatial.codeplex.com/ oldalról, majd később a szükséges projektekbe referenciázzuk őket.
  • Visual Studio 2010-től felfelé használhatjuk a NuGet csomagkezelő, ahonnan telepíthetjük az egyes modulokat a kiválasztott projektek alá. Nagy előnye, hogy csomag frissülése esetén automatikusan eljut hozzánk is az új csomag.

Windows Forms vezérlők

A DotSpatialt egyik legnagyobb előnye az előre megírt kontrolok, amiket a már jól megszokott Windows Formsos recept alapján akár vizuális szerkesztőben is összeállíthatunk.

DotSpatialt vezérlők telepítése

Ha szeretnénk használni a grafikus szerkesztőt, akkor mindenekelőtt hozzá kell adnunk a Toolbox-hoz a DotSpatialt vezérlőit.

  1. Jobbklikk a Toolboxon, majd válasszuk ki az Add Tab menüpontot.
  2. Nevezzük az előbb hozzáadott fület.
  3. Ismét jobbklikk az új fülön, és válasszuk ki a Choose Item opciót.
  4. A felugró ablakból válasszuk ki a DotSpatial.Controls.dll-t, ha nem találjuk a listából, akkor manuálisan adjuk hozz.

Most már ugyanúgy használhatjuk DotSpatial vezérlőit, mit a .NET alapértelmezettjeit.

Vezérlők demonstrációja

A DotSpatial vezérlők segítségével rendkívül gyorsan tudjuk alkalmazásunkat felruházni térinformatikai képességekkel. A következő alkalmazás remek példa az előbbiekre. Először készítsük el a felületet az alapértelmezett .NET, illetve a már ismertetett DotSpatial vezérlőkből.

<KÉP>

Miután megfelelően elneveztük a felületre elhelyezett elemeket, a hozzájuk tartozó kód mindössze ennyi:

 1 public partial class DesktopMapping : Form
 2     {
 3         private AppManager _AppManager;
 4 
 5         public DesktopMapping()
 6         {
 7             InitializeComponent();
 8 
 9             _AppManager = new AppManager();
10             _AppManager.LoadExtensions();
11         }
12 
13         private void uxOpenFile_Click(object sender, EventArgs e)
14         {
15             uxMap.AddLayer();
16         }
17 
18         private void uxZoomIn_Click(object sender, EventArgs e)
19         {
20             uxMap.ZoomIn();
21         }
22 
23         private void uxZoomWide_Click(object sender, EventArgs e)
24         {
25             uxMap.ZoomToMaxExtent();
26         }
27 
28         private void uxPan_Click(object sender, EventArgs e)
29         {
30             uxMap.FunctionMode = DotSpatial.Controls.FunctionMode.Pan;
31         }
32 
33         private void uxGenShp_Click(object sender, EventArgs e)
34         {
35             var rnd = new Random();
36             var pg = new Polygon[100];
37             var f = new Feature();
38             var fs = new FeatureSet(f.FeatureType);
39              
40             for (int i = 0; i < 100; i++)
41             {
42                 var center = new Coordinate((rnd.Next(50) * 360) - 180, (rnd.Next(60) * 180) - 90);
43                 var coord = new Coordinate[50];
44                 for (int ii = 0; ii < 50; ii++)
45                 {
46                     coord[ii] = new Coordinate(center.X + Math.Cos((ii * 10) * Math.PI / 10), center.Y + (ii * 10) * Math.PI / 10);
47                 }
48                 coord[35] = new Coordinate(coord[0].X, coord[0].Y);
49                 pg[i] = new Polygon(coord);
50                 fs.Features.Add(pg[i]);
51             }
52             fs.SaveAs("C:\\Temp\\test.shp", true);
53         }
54     }

Bővítmények

Lehetőségünk van bővítmények készítésére, amelyek akár a már kész alkalmazásokba is könnyedén integrálódnak (ilyen például a MapWindow).

Példaprogram beépülő modulra

A bemutatásra kerülő bővítménnyel lehetőségünk lesz vonalakat rajzolni, réteget létrehozni, illetve megjeleníthetünk velük kapcsolatos magassági adatokat. Elsőnek le kell töltenünk az online megtalálható sémával.

Diagram készítése

A magassági adatok megjelenítéséhez egy Windows Form alkalmazást készítünk.

1 public void Plot(double[] data)
2 {
3     chart1.Series.Clear();
4     var series = chart1.Series.Add("Elevation (meters)");
5     series.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
6     series.Points.DataBindY(data);
7 }

Raszter adatok kinyerése

A DotSpatial segítségével könnyedén kinyerhetjük a szükséges magassági adatokat.

 1 private static double GetElevation(IMapRasterLayer raster, Coordinate coordinate)
 2 {
 3     RcIndex rowColumn = raster.DataSet.Bounds.ProjToCell(coordinate);
 4     double elevation = raster.DataSet.Value[rowColumn.Row, rowColumn.Column];
 5     return elevation;
 6 }
 7 private static double GetDistance(double x1, double y1, double x2, double y2)
 8 {
 9     return Math.Sqrt(((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1)));
10 }

Koordináták kinyerése

 1 private List<Coordinate> GetCoordinatesFromLine(IMapLineLayer lineLayer)
 2 {
 3     IFeatureSet featureSet = lineLayer.DataSet;
 4 
 5     // The coordinates should be the first feature of the feature set.
 6     IList<Coordinate> lineCoordinates = featureSet.Features[0].Coordinates;
 7 
 8     // Though the original line may only have a few points, we split
 9     // each line segment into many points
10     List<Coordinate> pathCoordinates = new List<Coordinate>();
11 
12     for (int i = 0; i < lineCoordinates.Count - 1; i++)
13     {
14         Coordinate startCoord = lineCoordinates[i];
15         Coordinate endCoord = lineCoordinates[i + 1];
16         List<Coordinate> segmentCoordinates = SplitSegment(startCoord.X, startCoord.Y, endCoord.X, endCoord.Y);
17 
18         //add list of points from this line segment to the complete list
19         pathCoordinates.AddRange(segmentCoordinates);
20     }
21     return pathCoordinates;
22 }
23 
24 private static List<Coordinate> SplitSegment(double startX, double startY, double endX, double endY)
25 {
26     const int MinimumDistanceBetweenPoints = 15;
27 
28     double points = Math.Floor(GetDistance(startX, startY, endX, endY) / MinimumDistanceBetweenPoints);
29     int PointsPerSegment = (int)Math.Max(points, 1);
30 
31     double curX = startX;
32     double curY = startY;
33     double constXdif = ((endX - startX) / PointsPerSegment);
34     double constYdif = ((endY - startY) / PointsPerSegment);
35 
36     List<Coordinate> pathPointList = new List<Coordinate>(PointsPerSegment);
37     for (int i = 0; i <= PointsPerSegment; i++)
38     {
39         if (i == 0)
40         {
41             curX = startX;
42             curY = startY;
43         }
44         else
45         {
46             curX = curX + constXdif;
47             curY = curY + constYdif;
48         }
49         Coordinate coordinate = new Coordinate(curX, curY);
50         pathPointList.Add(coordinate);
51     }
52     return pathPointList;
53 }
54 
55 private void ShowElevation()
56 {
57     if (!map.GetRasterLayers().Any())
58     {
59         MessageBox.Show("Please add a DEM raster layer to the map.");
60         return;
61     }
62 
63     if (!map.GetLineLayers().Any())
64     {
65         MessageBox.Show("Please create a path by left clicking to add points and right-clicking to complete the path.");
66         return;
67     }
68 
69     try
70     {
71         IMapRasterLayer rasterLayer = map.GetRasterLayers().First();
72         IMapLineLayer pathLayer = map.GetLineLayers().First();
73         var coords = GetCoordinatesFromLine(pathLayer);
74 
75         double[] elevation = new double[coords.Count];
76         for (int i = 0; i < coords.Count; i++)
77         {
78             elevation[i] = GetElevation(rasterLayer, coords[i]);
79         }
80 
81         ChartForm chart = new ChartForm();
82         chart.Plot(elevation);
83         chart.Show();
84     }
85     catch (Exception ex)
86     {
87         MessageBox.Show("Error calculating elevation. The whole path should be inside the DEM area. " + ex.Message);
88     }
89 }

SimpleActionItem használata (menüelem)

 1 public void ButtonClick(object sender, EventArgs e)
 2 {
 3     // We're expecting this extension to only be run in a Windows Forms application.
 4     // We'll depend on a few Windows Forms (Map) features like MouseDown, so we cast
 5     // the App.Map as a Map and store a reference to it.
 6     map = App.Map as Map;
 7 
 8     // remove any existing path if needed.
 9     if (_PathLineLayer != null)
10         map.Layers.Remove(_PathLineLayer);
11 
12     _PathLineLayer = null;
13     _LineFeature = null;
14 
15     // Let the user know we are ready for them to set points by changing the cursor.
16     map.Cursor = Cursors.Cross;
17     map.MouseDown += map_MouseDown;
18 }

Vektor réteg létrehozása

 1 private void map_MouseDown(object sender, MouseEventArgs e)
 2 {
 3     if (e.Button == MouseButtons.Left)
 4     {
 5         // Encourage the user to select a raster, if they haven't done so.
 6         if (!map.GetRasterLayers().Any())
 7         {
 8             map.AddRasterLayer();
 9             map.ZoomToMaxExtent();
10             return;
11         }
12 
13         StartOrContinueDrawingPath(e.Location);
14         App.ProgressHandler.Progress(null, 0, "Point registered. Click again to add line segment. Right-click to finish.");
15     }
16     else if (e.Button == MouseButtons.Right)
17     {
18         EndDrawingPath();
19         ShowElevation();
20         App.ProgressHandler.Progress(null, 0, "Ready.");
21     }
22 }
23 
24 private IFeature AddLineFeatureSetToMap()
25 {
26     FeatureSet lineFeatureSet = new FeatureSet(FeatureType.Line);
27     lineFeatureSet.Projection = map.Projection;
28 
29     // Initialize the featureSet attribute table by creating columns
30     DataColumn column = new DataColumn("ID", typeof(short));
31     lineFeatureSet.DataTable.Columns.Add(column);
32     DataColumn column2 = new DataColumn("Number of Points", typeof(int));
33     lineFeatureSet.DataTable.Columns.Add(column2);
34     DataColumn column3 = new DataColumn("Description");
35     lineFeatureSet.DataTable.Columns.Add(column3);
36 
37     // Add the featureSet as map layer
38     _PathLineLayer = (MapLineLayer)map.Layers.Add(lineFeatureSet);
39     _PathLineLayer.Symbolizer = new LineSymbolizer(Color.Blue, 2);
40     _PathLineLayer.LegendText = "Path Layer";
41 
42     var newList = new List<Coordinate>();
43     LineString lineGeometry = new LineString(newList);
44 
45     // AddFeature creates the point and a row in the DataTable
46     return lineFeatureSet.AddFeature(lineGeometry);
47 }
48 
49 private void StartOrContinueDrawingPath(System.Drawing.Point mouseLocation)
50 {
51     Coordinate coord = map.PixelToProj(mouseLocation);
52 
53     if (_LineFeature == null)
54     {
55         // This is the first time we see a left click; create empty line feature.
56         _LineFeature = AddLineFeatureSetToMap();
57 
58         // Add first coordinate to the line feature.
59         _LineFeature.Coordinates.Add(coord);
60 
61         // Set the line feature attribute. This line may have multiple points,
62         // but there is only one row in the attribute table for the entire feature (line).
63         _LineFeature.DataRow["ID"] = 0;
64         _LineFeature.DataRow["Description"] = "Path (line)";
65     }
66     else
67     {
68         // Second or later click - add points to the existing feature
69         _LineFeature.BasicGeometry.Coordinates.Add(coord);
70         _LineFeature.ParentFeatureSet.InitializeVertices();
71 
72         // Draw the line.
73         map.ResetBuffer();
74 
75         // Update the attribute table.
76         _LineFeature.DataRow["Number of Points"] = _LineFeature.BasicGeometry.Coordinates.Count;
77     }
78 }
79 
80 private void EndDrawingPath()
81 {
82     // The path is complete.
83     map.ResetBuffer();
84     map.Cursor = Cursors.Arrow;
85     map.MouseDown -= map_MouseDown;
86     _LineFeature = null;
87 }