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);
}
}
}