ThinkGeo Cloud
ThinkGeo UI Controls
ThinkGeo Open Source
Help and Support
External Resources
ThinkGeo Cloud
ThinkGeo UI Controls
ThinkGeo Open Source
Help and Support
External Resources
This is an old revision of the document!
<Window x:Class="CustomRotationProjection.TestWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:my="clr-namespace:ThinkGeo.MapSuite.WpfDesktopEdition;assembly=WpfDesktopEdition" Title="Find Shortest Line from Point and Split Line" Height="640" Width="800" Loaded="Window_Loaded" > <Grid Height="Auto"> <Grid.ColumnDefinitions> <ColumnDefinition Width="778*" /> </Grid.ColumnDefinitions> <my:WpfMap Name="wpfMap1" /> <Button Height="28" Margin="0,12,20,0" Name="btnCalculate" VerticalAlignment="Top" HorizontalAlignment="Right" Width="246" Click="btnCalculate_Click" Content="Find Shortest Line from Point and Split Line" DataContext="{Binding}"></Button> <Button Height="28" HorizontalAlignment="Right" Margin="0,46,20,0" Name="btnClear" VerticalAlignment="Top" Width="246" Click="btnClear_Click" Content="Clear Results"></Button> <Button Height="28" HorizontalAlignment="Right" Margin="0,80,20,0" Name="btnMovePoint" VerticalAlignment="Top" Width="246" Click="btnEdit_Click" Content="Edit Test Features" /> </Grid> </Window>
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; using System.Collections.ObjectModel; using ThinkGeo.MapSuite.Core; using ThinkGeo.MapSuite.WpfDesktopEdition; namespace CustomRotationProjection { /// <summary> /// Interaction logic for TestWindow.xaml /// </summary> public partial class TestWindow : Window { public TestWindow() { InitializeComponent(); } private void Window_Loaded(object sender, RoutedEventArgs e) { //Add a base map (ThinkGeo's online World Map Kit). wpfMap1.MapUnit = GeographyUnit.DecimalDegree; WorldMapKitWmsWpfOverlay worldOverlay = new WorldMapKitWmsWpfOverlay(); wpfMap1.Overlays.Add("WMK", worldOverlay); //Build up the test data. InMemoryFeatureLayer testData = setupTestData(); //Make test line red in color. testData.ZoomLevelSet.ZoomLevel01.DefaultLineStyle = LineStyles.CreateSimpleLineStyle(GeoColor.SimpleColors.Red, 6, false); //Make test point dark green in color. testData.ZoomLevelSet.ZoomLevel01.DefaultPointStyle = PointStyles.CreateSimpleCircleStyle(GeoColor.StandardColors.DarkGreen, 12); //Apply the above styles to all zoom levels. testData.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20; //Create a MapShapeLayer that we can style individually and which will hold the results of the shortest line and split lines. MapShapeLayer results = new MapShapeLayer(); //Add the test data and results layers to a new layer overlay so they will show on top of the base map. LayerOverlay layerOverlay = new LayerOverlay(); layerOverlay.Layers.Add("TestData", testData); layerOverlay.Layers.Add("Results", results); wpfMap1.Overlays.Add("layerOverlay", layerOverlay); //Zoom into the test data area. wpfMap1.CurrentExtent = testData.GetBoundingBox(); wpfMap1.Refresh(); } private void btnCalculate_Click(object sender, RoutedEventArgs e) { //Get a reference to the results MapShapeLayer and clear it so we can display our new results. MapShapeLayer results = (MapShapeLayer)((LayerOverlay)wpfMap1.Overlays[["layerOverlay"]]).Layers[["Results"]]; results.MapShapes.Clear(); //Get a reference to the test data layer. InMemoryFeatureLayer testDataLayer = (InMemoryFeatureLayer)((LayerOverlay)wpfMap1.Overlays[["layerOverlay"]]).Layers[["TestData"]]; //Check to see if the test data has been edited. if (wpfMap1.EditOverlay.EditShapesLayer.InternalFeatures.Count > 0) { //Loop through the edited test data and update the test data layer. testDataLayer.EditTools.BeginTransaction(); foreach (Feature feature in wpfMap1.EditOverlay.EditShapesLayer.InternalFeatures) { testDataLayer.EditTools.Update(feature.CloneDeep()); } testDataLayer.EditTools.CommitTransaction(); //Clear out the EditOverlay since we are done editing. wpfMap1.EditOverlay.EditShapesLayer.InternalFeatures.Clear(); //Since we are done editing, turn visibility back on the for the layer overlay so we can see our test data again. wpfMap1.Overlays[["layerOverlay"]].IsVisible = true; } //Get the test point feature from the test data layer. Feature testPointFeature = testDataLayer.QueryTools.GetFeaturesByColumnValue("Name", "TestPoint", ReturningColumnsType.AllColumns)[[0]]; //Get the test line feature from the test data layer. Feature testLineFeature = testDataLayer.QueryTools.GetFeaturesByColumnValue("Name", "TestLine", ReturningColumnsType.AllColumns)[[0]]; //Take the test line feature and create a line shape so we can use line-specific APIs for finding the shortest line and line-on-line. LineShape testLine = new MultilineShape(testLineFeature.GetWellKnownText()).Lines[[0]]; //Calculate the shortest line between our test line and test point. LineShape shortestLineResult = testLine.GetShortestLineTo(testPointFeature.GetShape(), GeographyUnit.DecimalDegree).Lines[[0]]; //Take the result and create a MapShape so we can display the shortest line on the map in a blue color. MapShape shortestLine = new MapShape(new Feature(shortestLineResult)); shortestLine.ZoomLevels.ZoomLevel01.DefaultLineStyle = LineStyles.CreateSimpleLineStyle(GeoColor.SimpleColors.Blue, 4, false); shortestLine.ZoomLevels.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20; results.MapShapes.Add("ShortestLine", shortestLine); string message = "Length of Blue Line is: " + shortestLineResult.GetLength(GeographyUnit.DecimalDegree, DistanceUnit.Kilometer).ToString() + " KM" + '\n'; //Split the test line from the left side based on where the shortest line touches it. LineBaseShape leftSideOfLineResult = testLine.GetLineOnALine(new PointShape(testLine.Vertices[[0]]), new PointShape(shortestLineResult.Vertices[[0]])); //Make sure the split was valid and the closest point wasn't at the beginning or end of the line. if (leftSideOfLineResult.Validate(ShapeValidationMode.Simple).IsValid) { MapShape leftSideOfLine = new MapShape(new Feature(leftSideOfLineResult)); leftSideOfLine.ZoomLevels.ZoomLevel01.DefaultLineStyle = LineStyles.CreateSimpleLineStyle(GeoColor.StandardColors.Green, 2, false); leftSideOfLine.ZoomLevels.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20; results.MapShapes.Add("LeftSideofLine", leftSideOfLine); message += "Length of Green Line is: " + leftSideOfLineResult.GetLength(GeographyUnit.DecimalDegree, DistanceUnit.Kilometer).ToString() + " KM" + '\n'; } //Split the test line from the right side based on where the shortest line touches it. LineBaseShape rightSideOfLineResult = testLine.GetLineOnALine(new PointShape(shortestLineResult.Vertices[[0]]), new PointShape(testLine.Vertices[[testLine.Vertices.Count|- 1]])); //Make sure the split was valid and the closest point wasn't at the beginning or end of the line. if (rightSideOfLineResult.Validate(ShapeValidationMode.Simple).IsValid) { MapShape rightSideOfLine = new MapShape(new Feature(rightSideOfLineResult)); rightSideOfLine.ZoomLevels.ZoomLevel01.DefaultLineStyle = LineStyles.CreateSimpleLineStyle(GeoColor.SimpleColors.Yellow, 2, false); rightSideOfLine.ZoomLevels.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20; results.MapShapes.Add("RightSideofLine", rightSideOfLine); message += "Length of Yellow Line is: " + rightSideOfLineResult.GetLength(GeographyUnit.DecimalDegree, DistanceUnit.Kilometer).ToString() + " KM" + '\n'; } //Display the length of each line in kilometers. message += "Length of Red Line is: " + testLine.GetLength(GeographyUnit.DecimalDegree, DistanceUnit.Kilometer).ToString() + " KM"; wpfMap1.Refresh(); MessageBox.Show(message, "Results"); } private void btnClear_Click(object sender, RoutedEventArgs e) { //Get a reference to our overlay that has the test data in it. LayerOverlay layerOverlay = (LayerOverlay)wpfMap1.Overlays[["layerOverlay"]]; //Get a refrence to the results MapShapeLayer and clear out any prior results if they exist. MapShapeLayer results = (MapShapeLayer)layerOverlay.Layers[["Results"]]; results.MapShapes.Clear(); wpfMap1.Refresh(); } private void btnEdit_Click(object sender, RoutedEventArgs e) { //Check to make sure we haven't already added our test features to the EditShapesLayer. if (wpfMap1.EditOverlay.EditShapesLayer.InternalFeatures.Count == 0) { //Get a reference to the test data Layer. InMemoryFeatureLayer testData = ((InMemoryFeatureLayer)((LayerOverlay)wpfMap1.Overlays[["layerOverlay"]]).Layers[["TestData"]]); wpfMap1.EditOverlay.EditShapesLayer.Open(); //Check to see if this the first time we have ever edited the features. If so, add a column so that our name is stored correctly. if (wpfMap1.EditOverlay.EditShapesLayer.Columns.Count == 0) { wpfMap1.EditOverlay.EditShapesLayer.Columns.Add(new FeatureSourceColumn("Name")); } //Loop through all of our test data and add it to the edit overlay so we can interact with the test data. foreach (Feature feature in testData.QueryTools.GetAllFeatures(ReturningColumnsType.AllColumns)) { wpfMap1.EditOverlay.EditShapesLayer.InternalFeatures.Add(feature.CloneDeep()); } wpfMap1.EditOverlay.CalculateAllControlPoints(); //Turn off the LayerOverlay with our test data while we are editing it. wpfMap1.Overlays[["layerOverlay"]].IsVisible = false; //Refresh the map. wpfMap1.Refresh(); } } private InMemoryFeatureLayer setupTestData() { //Set up an in-memory layer with our test point and test line. InMemoryFeatureLayer testData = new InMemoryFeatureLayer(); testData.Open(); //Create a column on the layer to hold the name of the test feature. testData.Columns.Add(new FeatureSourceColumn("Name")); //Begin adding the test features to the layer. testData.EditTools.BeginTransaction(); //Create a test point based on an X and Y coordinate. Feature testPoint = new Feature(-0.1353814, 51.55651); //Set the name of the test feature to "TestPoint". testPoint.ColumnValues[["Name"]] = "TestPoint"; //Add the test point to the layer. testData.EditTools.Add(testPoint); //Create a test line based on a well-known text string containing the coordinates of the line. Feature testLine = new Feature("MULTILINESTRING((-0.395401840884043 51.4602079393573,-0.249570304960823 51.5620148606622,-0.0817264617284379 51.4588321701505,0.0352139208515025 51.5537602454212,0.168663533913317 51.4533290933232,0.27734930125232 51.5537602454212,0.392913914625438 51.4657110161846))"); //Set the name of the test feature to "TestLine". testLine.ColumnValues[["Name"]] = "TestLine"; //Add the test line to the layer. testData.EditTools.Add(testLine); //Commit the changes. testData.EditTools.CommitTransaction(); return testData; } } }