Introduction

A GeoFence is a virtual fence comprising a series of points surrounding a region (also known as a Polygon). This fence can be used to specify actions that are or are not permitted either inside or outside the enclosed region. In the example below we will create a GeoFence identifying a region (and its streets) that the GeoBase routing engine will not be permitted to use when creating a Route (an ordered sequence of stop locations). This fence will then be applied to a Route as a routing strategy (using the KeepOut property).

GeoFences are useful tools for avoiding areas of potential concern, such as public school zones, gated residential communities and military bases; or bypassing areas of congestion, such as around road works and construction sites.

In this tutorial we will create an application to route between two street addresses, then place a small GeoFence directly between the two addresses. When the KeepOut strategy is used, the routing engine will automatically re-route around the fenced area, using only those streets that it is permitted to route along.

Prerequisites

This tutorial assumes familiarity with Microsoft Visual Studio. You will need a copy of Visual Studio 2005 or later and a moderately specified desktop computer. You will also need a licensed copy of the Telogis GeoBase SDK. A 30-day free-of-charge trial may be downloaded from the GeoBase developer portal: http://dev.telogis.com/. Two versions of the trial SDK are available, one loaded with US (West Coast) map data, the other version loaded with map data for the UK. The locations used in this tutorial assume US data is used.

This tutorial also assumes that you are already familiar with the basics of creating a GeoBase-specific Visual Studio Project and adding a map control to a GeoBase project.

The Application

Create a new Visual Studio Project (a Windows Forms Application) called 'MyGeoFence'.

Add a reference to geobase.net.dll then, to simplify our code, add the following usings to the top of the project form (Form1.cs).

using Telogis.GeoBase;
using Telogis.GeoBase.Routing;
using Telogis.GeoBase.ImageUtils;
using Telogis.GeoBase.GeoFence;
using Telogis.GeoBase.Mapping;

Return to the 'Design' view (Shift+F7) and add the following controls to the form:

  • • A GeoBase map control named mapMain
  • • A button named buttonNoFence with the text 'Ignore GeoFence'
  • • A button named buttonFence with the text 'Obey GeoFence'

When run, your new application should appear similar to the screenshot below:

GeoFence Example

Next, add the following code to the top of the project such that the items are global (immediately above the Form1 constructor).

In this snippet we create a RendererList object to render objects (BoundingBoxes, PushPins and route highlights) on the map; BoundingBox, GeoFence and RectangleFence objects; two geocoded address locations (that will be used to set the corners of the keepout 'myBox' BoundingBox) and two RouteStop objects that will be used for our route.

// Create rendererlist
RendererList renderList = new RendererList();

// Create the new BoundingBox
BoundingBox myBox = new BoundingBox();

// Create GeoFence collection and Rectangle fence
GeoFenceCollection myFences = new GeoFenceCollection();
RectangleFence myFence = new RectangleFence();

// Find the corner locations of the BoundingBox
LatLon loc1 = GeoCoder.GeoCode("Beach & Arnold, Costa Mesa, Los Angeles", Country.USA)[0].Location;
LatLon loc2 = GeoCoder.GeoCode("Cove & Meyer, Costa Mesa, Los Angeles", Country.USA)[0].Location;

// We could also just specify LatLons if we wanted
// LatLon loc1 = new LatLon(33.650197, -117.930465);
// LatLon loc2 = new LatLon(33.643847, -117.921505);

// Create route start and end locations for our test route
RouteStop start = new RouteStop(new LatLon(33.650650, -117.924317));
RouteStop end = new RouteStop(new LatLon(33.643445, -117.925362));

Add the following code to the Form1 constructor (directly below InitializeComponent()). This will set our PushPin locations as the start and end points of the route, assign them suitable building icons, and add them to the renderer for display on the map.

Next, we set the corners of the KeepOut BoundingBox, and add the BoundingBox to the renderer, then set the map's center position and zoom level (a very close zoom, so streets will be visible).

// Create a pushpin at the start location
PushPin startl = new PushPin(start.Location);
// Give the pushpin a building icon
startl.Icon = Icons.Building7;
// Repeat for the end location...
PushPin endl = new PushPin(end.Location);
endl.Icon = Icons.Building7;

// Add the start and end pushpins to the renderlist
renderList.Add(startl);
renderList.Add(endl);			

// Add the address locations as the corners of our BoundingBox
// This is to show the area of interest. We don't do anything yet.
myBox.Add(loc1);
myBox.Add(loc2);
myBox.Color = Color.Black;

// Add the BoundingBox to the renderlist
renderList.Add(myBox);

// Set the default map renderer
mapMain.Renderer = renderList;

// Set the map center
mapMain.Center = new LatLon(33.647056, -117.925563);

// Set the map zoom -- very close
mapMain.Zoom = 1;

Return to the Design view in Visual Studio and add click events to the buttonNoFence and buttonFence buttons. These events will be used to trigger the generation of routes both with (buttonFence) and without (buttonNoFence) a KeepOut strategy applied.

Edit the buttonNoFence_Click method to match the code below. In it we clear the render list, reset the KeepOut BoundingBox (this time making it green rather than the initial black) and create a Route using a standard RoutingStrategyShortest strategy.

Then we add RenderArrow properties to make the direction of the route easier to see, and add the route's Directions to the render list. This shows the calculated route as a 'route highlight' on the map. 

Lastly, we recreate the PushPins that represent our route's start and end locations (these were set initially, but we cleared the renderlist so we place them again).

private void buttonNoFence_Click(object sender, EventArgs e) {
	// Clear the render list
	renderList.Clear();

	// Add the address locations as the corners of our 
	// keepout BoundingBox
	myBox.Add(loc1);
	myBox.Add(loc2);
	myBox.Color = Color.Green;

	// Add the BoundingBox to the renderlist
	renderList.Add(myBox);

	// Route from the start to the end location
	Route noFenceRte = new Route();
	noFenceRte.Start = start;
	noFenceRte.AddStopAtEnd(end);

	// Use a standard routing strategy -- ignore the
	// BoundingBox
	noFenceRte.Strategy = new RoutingStrategyShortest();
	noFenceRte.ForceRecalculate();
	Directions dirs = noFenceRte.GetDirections();

	// Configure render arrows so we know which direction to go
	dirs.RenderArrowColor = Color.White;
	dirs.RenderArrowLength = 12;
	dirs.RenderArrowWidth = 7;
	dirs.RenderArrowSpacing = 15;

	// Add the route to the render list
	renderList.Add(dirs);

	// Recreate pushpins at the start and end locations
	PushPin startl = new PushPin(start.Location);
	startl.Icon = Icons.Building7;
	PushPin endl = new PushPin(end.Location);
	endl.Icon = Icons.Building7;

	// Add the start and end locations to the renderlist
	renderList.Add(startl);
	renderList.Add(endl);

	// Force redraw
	mapMain.Invalidate();
}

Update the buttonFence_Click to match the code below. In it we repeat much of the content of the buttonNoFence_Click event, but this time we add the 'myBox' BoundingBox to the 'myFence' RectangleFence. This action sets the corners of the RectangleFence as the same corner locations used by the BoundingBox.

Next, we apply the 'myFence' GeoFence to the 'myFences' GeoFenceCollection. If we were to create more fences, each would typically be applied to the same collection. 

The GeoFenceCollection is then applied to the Route using the RoutingStrategy property KeepOut.

private void buttonFence_Click(object sender, EventArgs e) {
	// Clear the render list
	renderList.Clear();

	// Add the address locations as the corners of our BoundingBox
	myBox.Add(loc1);
	myBox.Add(loc2);
	myBox.Color = Color.Red;

	// Add the BoundingBox to the renderlist
	renderList.Add(myBox);

	// Get ready to use the keepOut strategy...
	// Set the rectangle fence using the BoundingBox
	myFence.Box = myBox;

	// Add the rectangle fence to the fences collection
	myFences.Add(myFence);

	// Route from the start to the end location
	Route FenceRte = new Route();
	FenceRte.Start = start;
	FenceRte.AddStopAtEnd(end);

	// Apply the keepout strategy to the route
	FenceRte.Strategy.KeepOut = myFences;
	FenceRte.ForceRecalculate();
	Directions dirs = FenceRte.GetDirections();

	// Configure render arrows so we know which direction to go
	dirs.RenderArrowColor = Color.White;
	dirs.RenderArrowLength = 12;
	dirs.RenderArrowWidth = 7;
	dirs.RenderArrowSpacing = 15;

	// Add the route to the render list
	renderList.Add(dirs);

	// Create pushpins at the start and end locations
	PushPin startl = new PushPin(start.Location);
	startl.Icon = Icons.Building7;
	PushPin endl = new PushPin(end.Location);
	endl.Icon = Icons.Building7;

	// Add the start and end locations to the renderlist
	renderList.Add(startl);
	renderList.Add(endl);

	// Force redraw
	mapMain.Invalidate();
}

NOTE: In the example above, we created a GeoFence using a RectangleFence that surrounds a rectangular area. It is also possible to fence a circular area using a CircleFence, an arbitrary area using a PolygonFence, or a specific street using a StreetLinkFence (that accepts a street Address, a LatLon location or a StreetLink).

For example, to restrict access to the corner of Ross Street and Meyer Place (effectively reproducing the results of the example above) we could use:

StreetLink link1 = GeoCoder.ReverseGeoCodeFull(
	GeoCoder.GeoCode("Ross & Meyer, Costa Mesa, Los Angeles", 
	Country.USA)[0].Location).StreetLink;
StreetLinkFence myLinkFence = new StreetLinkFence(link1);
myFences.Add(myLinkFence);

As the GeoFenceCollection implements the IMapRenderer interface, these fences can also be drawn directly on a map. For example:

renderList.Add(myFences);

Testing

Run the application. After clicking the buttonNoFence and buttonFence buttons the map will be updated with routes between the two addresses specified.

The route generated by buttonNoFence will not use a GeoFence, and can therefore travel directly across streets included within the inactive fence area (illustrated by a green box). The route generated by buttonFence, on the other hand, uses a GeoFence and a KeepOut strategy, and will route around this fenced area (illustrated by a red box).

No GeoFence or KeepOut strategy:

GeoFence Example No KeepOut.

Using a GeoFence and the KeepOut strategy:

GeoFence Example With KeepOut

Complete Code

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Telogis.GeoBase;
using Telogis.GeoBase.Routing;
using Telogis.GeoBase.ImageUtils;
using Telogis.GeoBase.GeoFence;
using Telogis.GeoBase.Mapping;

namespace MyGeoFence {
	public partial class Form1 : Form {
		// Create rendererlist
		RendererList renderList = new RendererList();

		// Create the new BoundingBox
		BoundingBox myBox = new BoundingBox();

		// Create GeoFence collection and Rectangle fence
		GeoFenceCollection myFences = new GeoFenceCollection();
		RectangleFence myFence = new RectangleFence();

		// Find the corner locations of the BoundingBox
		LatLon loc1 = GeoCoder.GeoCode("Beach & Arnold, Costa Mesa, Los Angeles", Country.USA)[0].Location;
		LatLon loc2 = GeoCoder.GeoCode("Cove & Meyer, Costa Mesa, Los Angeles", Country.USA)[0].Location;

		// We could also just specify LatLons if we wanted
		// LatLon loc1 = new LatLon(33.650197, -117.930465);
		// LatLon loc2 = new LatLon(33.643847, -117.921505);

		// Create route start and end locations for our test route
		RouteStop start = new RouteStop(new LatLon(33.650650, -117.924317));
		RouteStop end = new RouteStop(new LatLon(33.643445, -117.925362));

		public Form1() {
			InitializeComponent();

			// Create a pushpin at the start location
			PushPin startl = new PushPin(start.Location);
			// Give the pushpin a building icon
			startl.Icon = Icons.Building7;
			// Repeat for the end location...
			PushPin endl = new PushPin(end.Location);
			endl.Icon = Icons.Building7;

			// Add the start and end pushpins to the renderlist
			renderList.Add(startl);
			renderList.Add(endl);			

			// Add the address locations as the corners of our BoundingBox
			// This is to show the area of interest. We don't do anything yet.
			myBox.Add(loc1);
			myBox.Add(loc2);
			myBox.Color = Color.Black;

			// Add the BoundingBox to the renderlist
			renderList.Add(myBox);

			// Set the default map renderer
			mapMain.Renderer = renderList;

			// Set the map center
			mapMain.Center = new LatLon(33.647056, -117.925563);

			// Set the map zoom -- very close
			mapMain.Zoom = 1;
		}

		private void buttonNoFence_Click(object sender, EventArgs e) {
			// Clear the render list
			renderList.Clear();

			// Add the address locations as the corners of our 
			// keepout BoundingBox
			myBox.Add(loc1);
			myBox.Add(loc2);
			myBox.Color = Color.Green;

			// Add the BoundingBox to the renderlist
			renderList.Add(myBox);

			// Route from the start to the end location
			Route noFenceRte = new Route();
			noFenceRte.Start = start;
			noFenceRte.AddStopAtEnd(end);

			// Use a standard routing strategy -- ignore the
			// BoundingBox
			noFenceRte.Strategy = new RoutingStrategyShortest();
			noFenceRte.ForceRecalculate();
			Directions dirs = noFenceRte.GetDirections();

			// Configure render arrows so we know which direction to go
			dirs.RenderArrowColor = Color.White;
			dirs.RenderArrowLength = 12;
			dirs.RenderArrowWidth = 7;
			dirs.RenderArrowSpacing = 15;

			// Add the route to the render list
			renderList.Add(dirs);

			// Recreate pushpins at the start and end locations
			PushPin startl = new PushPin(start.Location);
			startl.Icon = Icons.Building7;
			PushPin endl = new PushPin(end.Location);
			endl.Icon = Icons.Building7;

			// Add the start and end locations to the renderlist
			renderList.Add(startl);
			renderList.Add(endl);

			// Force redraw
			mapMain.Invalidate();
		}

		private void buttonFence_Click(object sender, EventArgs e) {
			// Clear the render list
			renderList.Clear();

			// Add the address locations as the corners of our BoundingBox
			myBox.Add(loc1);
			myBox.Add(loc2);
			myBox.Color = Color.Red;

			// Add the BoundingBox to the renderlist
			renderList.Add(myBox);

			// Get ready to use the keepOut strategy...
			// Set the rectangle fence using the BoundingBox
			myFence.Box = myBox;

			// Add the rectangle fence to the fences collection
			myFences.Add(myFence);

			// Route from the start to the end location
			Route FenceRte = new Route();
			FenceRte.Start = start;
			FenceRte.AddStopAtEnd(end);

			// Apply the keepout strategy to the route
			FenceRte.Strategy.KeepOut = myFences;
			FenceRte.ForceRecalculate();
			Directions dirs = FenceRte.GetDirections();

			// Configure render arrows so we know which direction to go
			dirs.RenderArrowColor = Color.White;
			dirs.RenderArrowLength = 12;
			dirs.RenderArrowWidth = 7;
			dirs.RenderArrowSpacing = 15;

			// Add the route to the render list
			renderList.Add(dirs);

			// Create pushpins at the start and end locations
			PushPin startl = new PushPin(start.Location);
			startl.Icon = Icons.Building7;
			PushPin endl = new PushPin(end.Location);
			endl.Icon = Icons.Building7;

			// Add the start and end locations to the renderlist
			renderList.Add(startl);
			renderList.Add(endl);

			// Force redraw
			mapMain.Invalidate();
		}
	}
}

Published, Jul 7th 2016, 22:05

Tagged under: dotnet geobase routing navigation route optimization reverse geocoding maps