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
using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; namespace POIonRouteAdvanced { static class Program { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new TestForm()); } } }
using System; using System.Collections.ObjectModel; using System.Drawing; using System.Windows.Forms; using ThinkGeo.MapSuite.Core; using ThinkGeo.MapSuite.Routing; namespace POIonRouteAdvanced { public partial class TestForm : Form { private MapEngine mapEngine = new MapEngine(); private Bitmap bitmap = null; private ShapeFileFeatureLayer StreetLayer = null; private ShapeFileFeatureLayer poiLayer = null; private RoutingLayer routingLayer = null; private InMemoryFeatureLayer inMemoryFeatureLayer = null; private enum Side { LeftSide, RightSide }; public TestForm() { InitializeComponent(); } private void TestForm_Load(object sender, EventArgs e) { // Defines layer to render the Austin streets StreetLayer = new ShapeFileFeatureLayer(@"..\..\Data\austinstreets.shp"); StreetLayer.ZoomLevelSet.ZoomLevel01.DefaultLineStyle = LineStyles.LocalRoad3; StreetLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20; //defines layer for POI (Points of Interests) poiLayer = new ShapeFileFeatureLayer(@"..\..\Data\poi_2.shp"); poiLayer.ZoomLevelSet.ZoomLevel01.DefaultPointStyle = PointStyles.CreateSimpleSquareStyle(GeoColor.StandardColors.Gray, 12); poiLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20; mapEngine.StaticLayers.Add("AustinStreets", StreetLayer); mapEngine.StaticLayers.Add("AustinPOIs", poiLayer); // Define a Routing layer to render the route and stops routingLayer = new RoutingLayer(); StreetLayer.Open(); Feature feature1 = StreetLayer.FeatureSource.GetFeatureById("5156", ReturningColumnsType.NoColumns); Feature feature2 = StreetLayer.FeatureSource.GetFeatureById("8334", ReturningColumnsType.NoColumns); routingLayer.StartPoint = feature1.GetShape().GetCenterPoint(); routingLayer.EndPoint = feature2.GetShape().GetCenterPoint(); StreetLayer.Close(); mapEngine.DynamicLayers.Add("RoutingLayer", routingLayer); //InMemoryFeatureLayer for the POIs on the route (within tolerance and according to side of the route) inMemoryFeatureLayer = new InMemoryFeatureLayer(); inMemoryFeatureLayer.ZoomLevelSet.ZoomLevel01.DefaultPointStyle = PointStyles.CreateSimpleSquareStyle(GeoColor.StandardColors.OrangeRed, 12); inMemoryFeatureLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20; mapEngine.DynamicLayers.Add("SelectedPOIsLayer", inMemoryFeatureLayer); mapEngine.CurrentExtent = new RectangleShape(-97.7566, 30.3048, -97.7206, 30.2764); DrawImage(); } private void btnRoute_Click(object sender, EventArgs e) { //Finds the route between start point and end point. The rtg file needs to be build by Routing explorer if it has not been done already. RtgRoutingSource rtgRoutingSource = new RtgRoutingSource(@"..\..\Data\austinstreets.rtg"); RoutingEngine routingEngine = new RoutingEngine(rtgRoutingSource, StreetLayer.FeatureSource); routingLayer.Routes.Clear(); LineShape routeMultiLineShape = routingEngine.GetRoute(routingLayer.StartPoint, routingLayer.EndPoint).Route; routingLayer.Routes.Add(routeMultiLineShape); DrawImage(); btnFindPOIright.Enabled = true; btnFindaPOIleft.Enabled = true; } private void btnFindPOIright_Click(object sender, EventArgs e) { //Finds the Points of Interest within the tolerance and and on the right side of the route. FindPOIs(Side.RightSide); DrawImage(); } private void btnFindaPOIleft_Click(object sender, EventArgs e) { //Finds the Points of Interest within the tolerance and and on the left side of the route. FindPOIs(Side.LeftSide); DrawImage(); } private void FindPOIs(Side side) { inMemoryFeatureLayer.InternalFeatures.Clear(); //Distance Query to find the POIs within a distance of the route. poiLayer.Open(); Collection<Feature> features = poiLayer.QueryTools.GetFeaturesWithinDistanceOf(routingLayer.Routes[0], GeographyUnit.DecimalDegree, DistanceUnit.Meter, 100, ReturningColumnsType.NoColumns); poiLayer.Close(); //Loops thru the features within the tolerance to see if they are on the correct side. //Then adds the resulting features to the InMemoryFeatureLayer for display. inMemoryFeatureLayer.Open(); inMemoryFeatureLayer.EditTools.BeginTransaction(); foreach (Feature feature in features) { PointShape pointShape = (PointShape)feature.GetShape(); LineShape lineShape = (LineShape)routingLayer.Routes[0]; //We find the nearest line segment (made of two points) from the point feature (POI). LineShape nearestLineShape = FindNearestLineSegment(pointShape, lineShape, GeographyUnit.DecimalDegree); //Finds the side of the POI for that line segment and hence for the entire route. Side result = FindSide(nearestLineShape.Vertices[0], nearestLineShape.Vertices[1], new Vertex(pointShape)); //If on the correct side, adds the POI to the InMemoryFeatureLayer. if (result == side) { inMemoryFeatureLayer.EditTools.Add(feature); } } inMemoryFeatureLayer.EditTools.CommitTransaction(); inMemoryFeatureLayer.Close(); } //Finds the nearest line segment (made of two points). The nearest line segment is used because that can be used to determine the side of //a point for the whole route. private LineShape FindNearestLineSegment(PointShape pointShape, LineShape lineShape, GeographyUnit geographyUnit) { //We are using an InMemoryFeatureLayer to take advantage of its spatial query capabilities. InMemoryFeatureLayer tempInMemoryFeatureLayer = new InMemoryFeatureLayer(); tempInMemoryFeatureLayer.InternalFeatures.Add(new Feature(lineShape)); tempInMemoryFeatureLayer.Open(); //Finds the nearest LineShape of the MultilineShape of the route. Collection<Feature> features = tempInMemoryFeatureLayer.QueryTools.GetFeaturesNearestTo(pointShape, geographyUnit, 1, ReturningColumnsType.NoColumns); tempInMemoryFeatureLayer.Close(); LineShape nearestLineShape = (LineShape)features[0].GetShape(); //Uses the InMemoryFeatureLayer for its spatial query capabilities again. //To find the nearest line segment (made of two lines) from the nearest LineShape. tempInMemoryFeatureLayer.InternalFeatures.Clear(); int i; for (i = 0; i < nearestLineShape.Vertices.Count - 1; i += 1) { LineShape tempLineShape = new LineShape(); tempLineShape.Vertices.Add(nearestLineShape.Vertices[i]); tempLineShape.Vertices.Add(nearestLineShape.Vertices[i|+ 1]); tempInMemoryFeatureLayer.InternalFeatures.Add(new Feature(tempLineShape)); } tempInMemoryFeatureLayer.Open(); Collection<Feature> features2 = tempInMemoryFeatureLayer.QueryTools.GetFeaturesNearestTo(pointShape, geographyUnit, 1, ReturningColumnsType.NoColumns); tempInMemoryFeatureLayer.Close(); return (LineShape)features2[0].GetShape(); } //Math for finding on what side of a two point vector (line segment), a third point is located. On the right or on the left acording to the vector direction. private Side FindSide(Vertex lineVertex1, Vertex lineVertex2, Vertex vertex) { Side Result = Side.LeftSide; double a, b, yi, x1, y1, x2, y2, xp, yp; x1 = lineVertex1.X; y1 = lineVertex1.Y; x2 = lineVertex2.X; y2 = lineVertex2.Y; xp = vertex.X; yp = vertex.Y; a = (y2 - y1) / (x2 - x1); b = y1 - (a * x1); yi = (a * xp) + b; //Vertical line segment if (x1 == x2) { if (y1 < y2) { if (xp > x1) { Result = Side.RightSide; } } else { if (xp < x1) { Result = Side.RightSide; } } } //Horizontal line segment else if (y1 == y2) { if (x1 > x2) { if (yp > y1) { Result = Side.RightSide; } } else { if (yp < y1) { Result = Side.RightSide; } } } //Diagonal line else { if (x1 < x2) { if (yp < yi) { Result = Side.RightSide; } } else { if (yp > yi) { Result = Side.RightSide; } } } return Result; } private void DrawImage() { if (bitmap != null) { bitmap.Dispose(); } bitmap = new Bitmap(Map.Width, Map.Height); mapEngine.OpenAllLayers(); mapEngine.DrawStaticLayers(bitmap, GeographyUnit.DecimalDegree); mapEngine.DrawDynamicLayers(bitmap, GeographyUnit.DecimalDegree); mapEngine.CloseAllLayers(); Map.Image = bitmap; } private void ToolBar_ButtonClick(object sender, ToolBarButtonClickEventArgs e) { switch (e.Button.Tag.ToString()) { case "Zoom In": mapEngine.CurrentExtent.ScaleDown(50); break; case "Zoom Out": mapEngine.CurrentExtent.ScaleUp(50); break; case "Full Extent": mapEngine.CurrentExtent = ExtentHelper.GetDrawingExtent(new RectangleShape(-180.0, 83.0, 180.0, -90.0), Map.Width, Map.Height); break; case "Pan Left": mapEngine.CurrentExtent = ExtentHelper.Pan(mapEngine.CurrentExtent, PanDirection.Left, 20); break; case "Pan Right": mapEngine.CurrentExtent = ExtentHelper.Pan(mapEngine.CurrentExtent, PanDirection.Right, 20); break; case "Pan Up": mapEngine.CurrentExtent = ExtentHelper.Pan(mapEngine.CurrentExtent, PanDirection.Up, 20); break; case "Pan Down": mapEngine.CurrentExtent = ExtentHelper.Pan(mapEngine.CurrentExtent, PanDirection.Down, 20); break; default: break; } DrawImage(); } private void btnClose_Click(object sender, EventArgs e) { this.Close(); } private void Map_MouseMove(object sender, MouseEventArgs e) { //Displays the X and Y in screen coordinates. statusStrip1.Items["toolStripStatusLabelScreen"].Text = "X:" + e.X + " Y:" + e.Y; //Gets the PointShape in world coordinates from screen coordinates. PointShape pointShape = ExtentHelper.ToWorldCoordinate(mapEngine.CurrentExtent, new ScreenPointF(e.X, e.Y), Map.Width, Map.Height); //Displays world coordinates. statusStrip1.Items["toolStripStatusLabelWorld"].Text = "(world) X:" + Math.Round(pointShape.X, 4) + " Y:" + Math.Round(pointShape.Y, 4); } } }