Register  |  Login   Search
ThinkGeo - GPS Tracking and Mapping Solutions  |  Home  |  Cygnus Track  |  Blog
 
LivePerson Chat

Map Suite
Engine .NET GIS Framework

Common Questions and Answers About Map Suite Engine

Click on any of the frequently asked questions below to be taken to the answer.

If I have the latitude and longitude of a point, how can I plot it on a map?

All you need to do is, 1) Create a new point, 2) Add that point to the map.

Create a new Winforms project, add Engine reference to the project, and add the following code to the form's load event:

C#

// This first section is only to get a map of US to show.

Layer lyr = new Layer(@"..\sampledata\world\cntry02.shp", true);

lyr.ZoomLevelExtentUnit = ZoomLevelExtentUnits.DecimalDegrees;

lyr.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.ZoomLevel18;

lyr.ZoomLevel01.GeoStyle = GeoAreaStyles.GetSimpleAreaStyle(GeoColor.KnownColors.LightGray, GeoColor.KnownColors.Black, 1);

// Add the layer to the MapEngine.

mMapEngine.Layers.Add(lyr);

 

// This second section is all you need to plot a point if you have the latitude and longitude

PointMapShape pointMapShape = new PointMapShape();

pointMapShape.Shape = new PointShape(-119.09, 34.32);

pointMapShape.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.ZoomLevel18;

pointMapShape.ZoomLevel01.GeoStyle = GeoPointStyles.City1;

pointMapShape.ZoomLevel01.GeoTextStyle = GeoTextStyles.GetSimpleTextStyle(string.Empty, "Arial", 12, GeoFontStyle.Bold, GeoColor.KnownColors.Black);

pointMapShape.Name = "Los Angles";

// Add the point to the MapEngine.

mMapEngine.MapShapes.Add(pointMapShape);

 

//Define a bitmap.

Bitmap bitMap = new Bitmap(PictureBox1.Width, PictureBox1.Height);

Graphics g = Graphics.FromImage(bitMap);

MapLengthUnits unit = MapLengthUnits.DecimalDegrees;

RectangleR CurrentExtent = new RectangleR(-177.42, 99.53, 71.78, -77.56);

 

// Draw the current map onto the bitmap.

mMapEngine.GetMap(g, CurrentExtent, bitMap.Width, bitMap.Height, unit, 0);

mMapEngine.GetMapShapes(g, CurrentExtent, bitMap.Width, bitMap.Height, unit, 0);

 

g.Dispose();

VB.NET

' This first section is only to get a map of US to show.

Dim lyr As New Layer("..\sampledata\world\cntry02.shp", True)

lyr.ZoomLevelExtentUnit = ZoomLevelExtentUnits.DecimalDegrees

lyr.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.ZoomLevel18

lyr.ZoomLevel01.GeoStyle = GeoAreaStyles.GetSimpleAreaStyle(GeoColor.KnownColors.LightGray, GeoColor.KnownColors.Black, 1)

' Add the layer to the MapEngine.

mMapEngine.Layers.Add(lyr)

 

' This second section is all you need to plot a point if you have the latitude and longitude

Dim pointMapShape As New PointMapShape()

pointMapShape.Shape = New PointShape(-119.09, 34.32)

pointMapShape.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.ZoomLevel18

pointMapShape.ZoomLevel01.GeoStyle = GeoPointStyles.City1

pointMapShape.ZoomLevel01.GeoTextStyle = GeoTextStyles.GetSimpleTextStyle(String.Empty, "Arial", 12, GeoFontStyle.Bold, GeoColor.KnownColors.Black)

pointMapShape.Name = "Los Angles"

' Add the point to the MapEngine.

mMapEngine.MapShapes.Add(pointMapShape)

 

'Define a bitmap.

Dim bitMap As New Bitmap(PictureBox1.Width, PictureBox1.Height)

Dim g As Graphics = Graphics.FromImage(bitMap)

Dim unit As MapLengthUnits = MapLengthUnits.DecimalDegrees

Dim CurrentExtent As New RectangleR(-177.42, 99.53, 71.78, -77.56)

 

' Draw the current map onto the bitmap.

mMapEngine.GetMap(g, CurrentExtent, bitMap.Width, bitMap.Height, unit, 0)

mMapEngine.GetMapShapes(g, CurrentExtent, bitMap.Width, bitMap.Height, unit, 0)

 

g.Dispose() 

Back to Top

I would like to have more custom properties (like a tag property) on a map shape object. How can I add my own properties?

Adding custom properties is quite easy. All you have to do is inherit from one of the classes and add your own custom properties, like in the following code:

C#

using MapSuite;

using MapSuite.Geometry;

 

public class MyPointMapShape : PointMapShape

{

private string tag = string.Empty;

 

public MyPointMapShape(PointShape pointShape, PointSymbol pointSymbol)

:base(pointShape,pointSymbol)

{

}

 

public string Tag

{

get

{

return tag;

}

set

{

tag = value;

}

}

}

VB.NET

Imports MapSuite

Imports MapSuite.Geometry

 

Public Class MyPointMapShape

Inherits PointMapShape

Private m_tag As String = String.Empty

 

Public Sub New(ByVal pointShape As PointShape, ByVal pointSymbol As PointSymbol)

MyBase.New(pointShape, pointSymbol)

End Sub

 

Public Property Tag() As String

Get

Return m_tag

End Get

Set(ByVal value As String)

m_tag = value

End Set

End Property

End Class  

From here, you can add as many custom properties as you would like.

Back to Top

How do I convert screen coordinates into world coordinates?

The map control has a method ToWorldCoordinate which takes in a PointF object (a point in canvas / screen coordinates). Returned is a PointR object (a point in world coordinates).

C#

System.Drawing.PointF controlPointF = new System.Drawing.PointF(45, 34);

// PictureBox1 is the container of Bitmap get from MapEngine.

PointR pointR = mMapEngine.ToWorldCoordinate(controlPointF,PictureBox1.Width, PictureBox1.Height);

PointShape p0 = new PointShape(pointR.X, pointR.Y);

VB.NET

Dim controlPointF As New System.Drawing.PointF(45, 34)

' PictureBox1 is the container of Bitmap get from MapEngine.

Dim pointR As PointR = mMapEngine.ToWorldCoordinate(controlPointF, PictureBox1.Width, PictureBox1.Height)

Dim p0 As New PointShape(pointR.X, pointR.Y)

Back to Top

How do I convert world coordinates into screen coordinates?

The map control has a method ToCanvasCoordinate which takes in a PointR object (a point in world coordinates). Returned is a PointF object (a point in canvas / screen coordinates).

C#

PointShape pointShape = new PointShape(-119.09, 34.32);

// PictureBox1 is the container of Bitmap get from MapEngine.

System.Drawing.PointF screetPoint = mMapEngine.ToCanvasCoordinate(pointShape.X, pointShape.Y,PictureBox1.Width, PictureBox1.Height);

VB.NET

Dim pointShape As New PointShape(-119.09, 34.32)

' PictureBox1 is the container of Bitmap get from MapEngine.

Dim screetPoint As System.Drawing.PointF = mMapEngine.ToCanvasCoordinate(pointShape.X, pointShape.Y, PictureBox1.Width, PictureBox1.Height)

Back to Top

I see a layer can have different zoomlevels. What would I use this feature for?

Imagine you have an application which maps a traveler's journey between two points. You would, likely, start by showing the entire US as the full extent. At this level, you would show the states and maybe the interstate and US highways. As the user zooms in to a single state, you might show state highways. As they zoom in more you might show county roads. As they zoom in so they are looking at a city, you could show all the city streets.

In such an application you would need to setup different zoomlevels to control what the is shown to the user and when (otherwise, the map would be too cluttered). In this example, you would setup a zoomlevel to show states, interstate and US highways. This zoomlevel would be setup to show when the user was at any zoom level (say between 30,000 miles across and 0 miles across). Then another zoomlevel would be created to show state highways when the user is zoomed into the state level (say between 750 miles across and 0 miles across). You keep setting up more and more zoomlevels like this. Your final zoomlevel would be to show the city streets when the user is zoomed to between 10 miles across and 0 miles across). You may notice that all of the zoomlevels here are set to keep showing as the user zooms in (the second parameter is 0 miles across). You could also set one or more zoomlevels to stop showing once zoomed in too close to something.

The Misc sample named "ZoomLevels" can show you in more detail how to use zoomlevels.

Back to Top

How can I get information about point or feature from a dbf file?

Using Layer.DataQuery you can get all the information available in the dbf file. This routine takes in either a SQL string or record number(s). If you have the record number of the point you want information about (23 in this example), you would use the following code to get the data about that point from the dbf file into a DataTable object:

C#

DataTable dt = mMapEngine.Layers[0].DataQuery(23, false);

VB.NET

Dim dt As DataTable = mMapEngine.Layers(0).DataQuery(23, False) 

The Querying sample "Combination Query" will show you more detail on this topic.

Back to Top

Once I have a record number, how can I get the shape for that record?

Using Layer.GetShape you can get the shape object for a record (in this example, 23). The following code would accomplish this:

C#

BaseShape shape = mMapEngine.Layers[0].GetShape(23);

VB.NET

Dim shape As BaseShape = mMapEngine.Layers(0).GetShape(23) 

You could also use Layer.DataQuery with the following code (this will return all the dbf file information as well as the shape):

C#

DataTable dt = mMapEngine.Layers[0].DataQuery(23, false);

VB.NET

Dim dt As DataTable = mMapEngine.Layers(0).DataQuery(23, False) 

Back to Top

How can I display my data so each item falls within some group? For example, if I have several cities with different populations, how could I group these cities into the categories of small, medium, and large, each with its own symbol on the map?

To accomplish this you would use class breaks. You can see the Rendering sample named "Label Value Renderer" (or another one is Class Break Renderer) for more detail. Basically, you need to create a series of class breaks and one class break cap to group the data. For example, let's use the example of cities, like in Label Value Renderer. In that sample, each listed city falls into one of five categories: Less than 500,000; 500,000 - 999,999; 1,000,000 - 1,999,999; 2,000,000 - 4,999,999; and 5,000,000 and over. When we setup the class breaks, you'll see how it works. The code below accomplishes the task.

C#

' First we need to setup the zoomlevel and collection.

Dim zoomLevel As New ZoomLevel(10000, 2500)

Dim classBreaks As New SymbolClassBreakCollection()

 

' Create first break, which is 'Under 500,000' and add it to the collection.

Dim break1 As New SymbolClassBreakRenderer.ClassBreak(500000, mCustomPointSymbol1)

classBreaks.Add(break1)

 

' Create second break, which is 'Under 1,000,000' and add it to the collection

Dim break2 As New SymbolClassBreakRenderer.ClassBreak(1000000, mCustomPointSymbol2)

classBreaks.Add(break2)

 

' Create third break, which is 'Under 2,000,000' and add it to the collection

Dim break3 As New SymbolClassBreakRenderer.ClassBreak(2000000, mCustomPointSymbol3)

classBreaks.Add(break3)

 

' Create cap, which will handle the final two categories. Every class break collection must end with a cap

' In this case, the cap says, everything over 5,000,000 should get Symbol5 and under 5,000,000 will get Symbol4

Dim cap As New SymbolClassBreakRenderer.ClassBreakCap(5000000, mCustomPointSymbol5, mCustomPointSymbol4)

classBreaks.Add(cap)

 

' Now, we just add the class break collection to a renderer and add the renderer to the zoomlevel.

Dim rend As New SymbolClassBreakRenderer("population", classBreaks)

zoomLevel.GeoStyle.SymbolRenderers.Add(rend)

 

' At this point, we have setup our class breaks. 

VB.NET

' First we need to setup the zoomlevel and collection.

Dim zoomLevel As New ZoomLevel(10000, 2500)

Dim classBreaks As New SymbolClassBreakCollection()

 

' Create first break, which is 'Under 500,000' and add it to the collection.

Dim break1 As New SymbolClassBreakRenderer.ClassBreak(500000, mCustomPointSymbol1)

classBreaks.Add(break1)

 

' Create second break, which is 'Under 1,000,000' and add it to the collection

Dim break2 As New SymbolClassBreakRenderer.ClassBreak(1000000, mCustomPointSymbol2)

classBreaks.Add(break2)

 

' Create third break, which is 'Under 2,000,000' and add it to the collection

Dim break3 As New SymbolClassBreakRenderer.ClassBreak(2000000, mCustomPointSymbol3)

classBreaks.Add(break3)

 

' Create cap, which will handle the final two categories. Every class break collection must end with a cap

' In this case, the cap says, everything over 5,000,000 should get Symbol5 and under 5,000,000 will get Symbol4

Dim cap As New SymbolClassBreakRenderer.ClassBreakCap(5000000, mCustomPointSymbol5, mCustomPointSymbol4)

classBreaks.Add(cap)

 

' Now, we just add the class break collection to a renderer and add the renderer to the zoomlevel.

Dim rend As New SymbolClassBreakRenderer("population", classBreaks)

zoomLevel.GeoStyle.SymbolRenderers.Add(rend)

 

' At this point, we have setup our class breaks.  

When you are this far, you have the class breaks setup. It is important that you remember that the sequence is quite important. The sequence in which the class breaks are added to the collection will determine into which class each value falls. The logic will work something like the following.

  • For each value to be put into a class break (for each city in this example)
  • Compare to each class break
  • Does the current value fall below the current class break level?
  • If yes, then the current value is assigned to the current class break, go to the next value (city).
  • If no, then go to the next class break.
  • If we get to the class break cap and the current value is higher than the cap (5,000,000 in this example) then assign to the highest class break, regardless of how high the value is.

So, if you add the class breaks in a different order, expect different results.

Back to Top

How can I display my data so each item is represented with a special symbol based on a exact textual match (not categories, classes or ranges)? For example, a lake should be blue, a dry lake should be brown, etc.

To accomplish this you would use symbol value renderers. You can see the Rendering sample named "Value Renderer" for more detail. You need to create a collection to hold the values to match and then setup a symbol for each value ('Lake', 'Dry Lake', etc.). See the following code.

C#

// First we need to setup the zoomlevel and collection.

ZoomLevel zoomLevel = new ZoomLevel(10000, 0);

SymbolValueCollection values = new SymbolValueCollection();

SymbolValueRenderer.Value val;

AreaSymbol sym;

 

// Add renderer value for any record named "Lake". This will be a simple light sky blue color for a lake.

sym = new AreaSymbol(new GeoPen(GeoColor.KnownColors.Black), new GeoSolidBrush(GeoColor.KnownColors.LightSkyBlue));

val = new SymbolValueRenderer.Value("Lake", sym);

values.Add(val);

 

// Add renderer value for any record named "Dry Lake". This will be an actual graphic that looks like a dry lake.

Bitmap bmp = new Bitmap(@"..\SampleData\Texures\rust pebbles.bmp");

sym = new AreaSymbol(new GeoPen(GeoColor.FromArgb(0,0,0,0)),new GeoTextureBrush(bmp));

val = new SymbolValueRenderer.Value("Dry Lake", sym);

values.Add(val);

 

// Now, we must create the renderer (collection of values) and add it to the zoomlevel.

SymbolValueRenderer rend = new SymbolValueRenderer("Feature", values);

zoomLevel.GeoStyle.SymbolRenderers.Add(rend);

 

// At this point, lakes and dry lakes are configured to show using the symbols we specified

// All you need to do now is add the zoomlevel to the layer and add the layer to the map.

VB.NET

' First we need to setup the zoomlevel and collection.

Dim zoomLevel As New ZoomLevel(10000, 0)

Dim values As New SymbolValueCollection()

Dim val As SymbolValueRenderer.Value

Dim sym As AreaSymbol

 

' Add renderer value for any record named "Lake". This will be a simple light sky blue color for a lake.

sym = New AreaSymbol(New GeoPen(GeoColor.KnownColors.Black), New GeoSolidBrush(GeoColor.KnownColors.LightSkyBlue))

val = New SymbolValueRenderer.Value("Lake", sym)

values.Add(val)

 

' Add renderer value for any record named "Dry Lake". This will be an actual graphic that looks like a dry lake.

Dim bmp As New Bitmap("..\SampleData\Texures\rust pebbles.bmp")

sym = New AreaSymbol(New GeoPen(GeoColor.FromArgb(0, 0, 0, 0)), New GeoTextureBrush(bmp))

val = New SymbolValueRenderer.Value("Dry Lake", sym)

values.Add(val)

 

' Now, we must create the renderer (collection of values) and add it to the zoomlevel.

Dim rend As New SymbolValueRenderer("Feature", values)

zoomLevel.GeoStyle.SymbolRenderers.Add(rend)

 

' At this point, lakes and dry lakes are configured to show using the symbols we specified

' All you need to do now is add the zoomlevel to the layer and add the layer to the map. 

Back to Top

How can I use my own rendering logic when the symbol representing an place's location is being drawn?

Setting up your own rendering logic for this is quite easy. You can see the Rendering sample named "Custom Symbols" for a more detailed example on how to accomplish this but simply put, all you need to do is create a module level variable of type PointSymbol and then wire-up a custom draw event to handle that object's drawing. The following code should make it clearer:

C#

// Module-level variable to represent the point symbol for each location.

private PointSymbol mCustomPointSymbol;


// Then, create the custom draw routine
private void mCustomPointSymbol_CustomDraw(Graphics graphics, PointF pointF, PointSymbol symbol)

{

int xCoordinate = Convert.ToInt32(pointF.X - 7);

int yCoordinate = Convert.ToInt32(pointF.Y - 7);

Rectangle rect = new Rectangle(xCoordinate, yCoordinate, 14, 14);

 

GraphicsPath graphicsPath = new GraphicsPath();

graphicsPath.AddEllipse(rect);

 

PathGradientBrush brush = new PathGradientBrush(graphicsPath.PathPoints);

 

Color[] colors = { Color.FromArgb(170, 37, 137, 43) };

brush.CenterColor = Color.FromArgb(255, 32, 115, 36);

brush.SurroundColors = colors;

brush.FocusScales = new PointF(Convert.ToSingle(0.01), Convert.ToSingle(0.01));

 

graphics.FillEllipse(brush, rect);

brush.Dispose();

}



// Then, in the page’s load event, instantiate the variable and wire-up the custom draw routine
protected void Page_Load (object sender, System.EventArgs e)
{

mCustomPointSymbol = new PointSymbol(PointStyleEnum.Custom);
mCustomPointSymbol.CustomDraw += new PointSymbol.CustomDrawEventHandler(mCustomPointSymbol_CustomDraw);
}

VB.NET

' Module-level variable to represent the point symbol for each location.

Private mCustomPointSymbol As PointSymbol

' Then, create the custom draw routine

Private Sub mCustomPointSymbol_CustomDraw(ByVal graphics As Graphics, ByVal pointF As PointF, ByVal symbol As PointSymbol)

Dim xCoordinate As Integer = Convert.ToInt32(pointF.X - 7)

Dim yCoordinate As Integer = Convert.ToInt32(pointF.Y - 7)

Dim rect As New Rectangle(xCoordinate, yCoordinate, 14, 14)

 

Dim graphicsPath As New GraphicsPath()

graphicsPath.AddEllipse(rect)

 

Dim brush As New PathGradientBrush(graphicsPath.PathPoints)

 

Dim colors As Color() = {Color.FromArgb(170, 37, 137, 43)}

brush.CenterColor = Color.FromArgb(255, 32, 115, 36)

brush.SurroundColors = colors

brush.FocusScales = New PointF(Convert.ToSingle(0.01), Convert.ToSingle(0.01))

 

graphics.FillEllipse(brush, rect)

brush.Dispose()

End Sub 

 

'Then, in the page’s load event, instantiate the variable and wire-up the custom draw routine

Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)

mCustomPointSymbol = New PointSymbol(PointStyleEnum.[Custom])

AddHandler mCustomPointSymbol.CustomDraw, AddressOf mCustomPointSymbol_CustomDraw

End Sub 

Back to Top

How can I have items labeled differently based on a value in a field in the shape file? For example, if I have several cities in each country in Europe, I want to show capitals in a larger font than non-capitals.

To accomplish this you would use the label value renderer. You can see the Rendering sample named "Label Value Renderer" for more detail. You need to create a label value collection and add to that collection one label value for each value to be match. In this example, we will have two label values; one for "Y" and one for "N" in the field named "Capital." The code below does just that.

C#

// First we need to setup the zoomLevel and collection
ZoomLevel t2 = new ZoomLevel(2500, 0);

LabelValueCollection col = new LabelValueCollection();

LabelValueRenderer.LabelValue val;

TextSymbol sym;

 

// Setup for capitals

sym = new TextSymbol(new GeoFont("Arial", 12, GeoFontStyle.Bold), new GeoSolidBrush(GeoColor.KnownColors.Black), 0, -8);

val = new LabelValueRenderer.LabelValue("Y", sym);

col.Add(val);

 

// Setup for non-capitals

sym = new TextSymbol(new GeoFont("Arial", 8, GeoFontStyle.Bold), new GeoSolidBrush(GeoColor.KnownColors.Black), 0, -6);

val = new LabelValueRenderer.LabelValue("N", sym);

col.Add(val);

 

// Create renderer, testing field "Capital" but displaying field "Name"

LabelValueRenderer rend = new LabelValueRenderer("Capital", "Name", col);

 

// Add renderer to the zoomLevel

t2.GeoTextStyle.LabelRenderers.Add(rend);

VB.NET

Dim t2 As New ZoomLevel(2500, 0)

Dim col As New LabelValueCollection()

Dim val As LabelValueRenderer.LabelValue

Dim sym As TextSymbol

 

' Setup for capitals

sym = New TextSymbol(New GeoFont("Arial", 12, GeoFontStyle.Bold), New GeoSolidBrush(GeoColor.KnownColors.Black), 0, -8)

val = New LabelValueRenderer.LabelValue("Y", sym)

col.Add(val)

 

' Setup for non-capitals

sym = New TextSymbol(New GeoFont("Arial", 8, GeoFontStyle.Bold), New GeoSolidBrush(GeoColor.KnownColors.Black), 0, -6)

val = New LabelValueRenderer.LabelValue("N", sym)

col.Add(val)

 

' Create renderer, testing field "Capital" but displaying field "Name"

Dim rend As New LabelValueRenderer("Capital", "Name", col)

 

' Add renderer to the zoomLevel

t2.GeoTextStyle.LabelRenderers.Add(rend)  

Back to Top

I see that a map can have multiple layers. Why would I use multiple layers?

Since a layer is the object that holds the data (that is a layer has one and only one shape file as its data source) if you want to have multiple data sources then you need multiple layers. The Misc sample named "ZoomLevels" can show you more details about this. In this sample, you will see six layers created. One layer has the streets of Austin, one layer has the US highways, one layer has the details about the US states, etc. The zoomLevels in this sample just, in effect, tell each layer to render only at certain zoom factors. The point is that each layer actually has the data from the shape file. So, multiple shape files means multiple layers.

Back to Top

How can I print a map?

If you just want to print the map, it is quite easy. The Rendering sample named "Label Placement" shows how it is done, but the code is the following:

C#

using System.Drawing.Printing;

 

// Create a print object for printing

private PrintPreviewDialog print = new PrintPreviewDialog();

 

// Add these codes add Form.Load event

PrintDocument document = new PrintDocument();

document.PrintPage += new PrintPageEventHandler(document_PrintPage);

print.Document = document;

 

// Add this statment when you want to print

print.ShowDialog(); 

 

void document_PrintPage(object sender, PrintPageEventArgs e)

{

mMapEngine.GetMap(e.Graphics, mCurrentExtent, PictureBox1.Width, PictureBox1.Height, MapLengthUnits.DecimalDegrees, 0);

}

VB.NET

Imports System.Drawing.Printing

 

' Create a print object for printing

Private print As New PrintPreviewDialog()

 

' Add these codes add Form.Load event

Dim document As New PrintDocument()

AddHandler document.PrintPage, AddressOf document_PrintPage

Print.Document = document


' Add this statment when you want to print

print.ShowDialog() 

 

Private Sub document_PrintPage(ByVal sender As Object, ByVal e As PrintPageEventArgs)

mMapEngine.GetMap(e.Graphics, mCurrentExtent, PictureBox1.Width, PictureBox1.Height, MapLengthUnits.DecimalDegrees, 0)

End Sub

At this point, the user will see the print preview dialog and can print just by pressing the print button.

Back to Top

How can I print a map if I want to include my own logic? For example, if I want to include a legend or some additional text?

The Misc sample named "Printing" shows how it is done but the basics are this. You create a module level variable to hold the print document. You also wire up the PrintPage event so that when the map prints, you will get an event and you can add all the logic you want. The following code should make it clearer:

C#

// Module-level variable
private PrintDocument mPrintDocument = new PrintDocument();

// Logic when you want to show the print preview window
PrintPreviewDialog print = new PrintPreviewDialog();
mPrintDocument.DefaultPageSettings.Landscape = true;
print.Document = mPrintDocument;
print.ShowDialog();

// You'll also need to add this to the form's load event to wire up the custom print event
mPrintDocument.PrintPage += PrintPageEventHandler (mPrintDocument_PrintPage);

// Finally, you will need to add the routine for the event
private void mPrintDocument_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
// Put your own custom drawing logic here

// Here we will use a simplified version of the code in the printing sample
// First, draw the map with a border
Bitmap b = Map1.GetBitmap(820, 580, false);
e.Graphics.DrawImage(b, 200, 120);
e.Graphics.DrawRectangle(new Pen(Color.Black, 2), new Rectangle(200, 120, Misc.GetBitmapScreenWidth(b),
Misc.GetBitmapScreenHeight(b)));

// Next draw a title on the page
e.Graphics.DrawString("This is the title for the page", new Font("Arial",15,FontStyle.Bold),
new SolidBrush(Color.Black), 310, 54);

// Add as much logic as you would like
}

VB.NET

'-- Module-level variable
private WithEvents mPrintDocument As New PrintDocument()

'-- Logic when you want to show the print preview window
Dim print As New PrintPreviewDialog()
mPrintDocument.DefaultPageSettings.Landscape = True
print.Document = mPrintDocument
print.ShowDialog()

'-- Finally, you will need to add the routine for the event
private Sub mPrintDocument_PrintPage(ByVal sender as Object, _
ByVal e as System.Drawing.Printing.PrintPageEventArgs)
'-- Put your own custom drawing logic here

'-- Here we will use a simplified version of the code in the printing sample
' First, draw the map with a border
Dim b As Bitmap = Map1.GetBitmap(820, 580, False)
e.Graphics.DrawImage(b, 200, 120)
e.Graphics.DrawRectangle(New Pen(Color.Black, 2), New Rectangle(200, 120, GetBitmapScreenWidth(b),
GetBitmapScreenHeight(b)))

'-- Next draw a title on the page
e.Graphics.DrawString("This is the title for the page", New Font("Arial",15,FontStyle.Bold),
New SolidBrush(Color.Black), 310, 54)

'-- Add as much logic as you would like
End Sub

At this point, the user will see the print preview dialog and can print just by pressing the print button. All of your custom logic will be shown in the print preview dialog.

Back to Top

What are map shapes and how can I use them?

The Misc sample named "Track Shapes" will show you how to create map shapes based on a track shape (a shape a user draws). A map shape is a shape that is added via code and not from a shape file. That is, mostly shapes will be added from shape files (roads, buildings, etc.) but you might want to have your own shapes. Your own shapes might include proposed buildings or even vehicles driving down the street.

Map shapes can be easily moved and reside outside the context of layers. Map shapes are on the map, not on a layer. Let's add some map shapes to the map.

The following code should make it clear:

C#

mCurrentExtent = new RectangleR(-177.42, 99.53, 71.78, -77.56);

 

PointShape pointShape = new PointShape(-97.734, 30.284);

PointMapShape pointMapShape = new PointMapShape(pointShape);

pointMapShape.Symbols.Add(new PointSymbol(PointStyleEnum.Circle, new GeoSolidBrush(GeoColor.KnownColors.Blue), 8));

mMapEngine.MapShapes.Add(pointMapShape);

 

Bitmap bitMap = new Bitmap(400, 300);

Graphics g = Graphics.FromImage(bitMap);

 

mMapEngine.GetMapShapes(g, mCurrentExtent, 400, 300, MapLengthUnits.DecimalDegrees, 0);

g.Dispose(); 

VB.NET

mCurrentExtent = New RectangleR(-177.42, 99.53, 71.78, -77.56)

 

Dim pointShape As New PointShape(-97.734, 30.284)

Dim pointMapShape As New PointMapShape(pointShape)

pointMapShape.Symbols.Add(New PointSymbol(PointStyleEnum.Circle, New GeoSolidBrush(GeoColor.KnownColors.Blue), 8))

mMapEngine.MapShapes.Add(pointMapShape)

 

Dim bitMap As New Bitmap(400, 300)

Dim g As Graphics = Graphics.FromImage(bitMap)

 

mMapEngine.GetMapShapes(g, mCurrentExtent, 400, 300, MapLengthUnits.DecimalDegrees, 0)

g.Dispose() 

As you can see, there is very little code to actually add a map shape to a map. Most of the code will depend on how you want to store the data about the points the user selected.

Back to Top

How can I define my own custom labeling plug-in?

The Rendering sample named "Custom Labeler" goes over this is greater detail but what you will need to do is create a class that inherits from MapSuite.ILabeler. There are several methods to implement, all named DrawLabels (taking in different parameters). In the sample, you will see DrawLabels implemented for Polygons and MultiLines. The code for polygons is below:

C#

// Class declaration
public class CustomLabeler : MapSuite.ILabeler

{

// DrawLabels routine

public void DrawLabels(Graphics g, Array[] TextSymbolArrays, Array[] SymbolArray, MapSuite.Geometry.PolygonF[] Polygons, ref SimplePolygonF[] LabeledAreas, int CanvasWidth, int CanvasHeight)

{

// Drawing labels for polygons

StringFormat Format = new StringFormat();

Format.Alignment = StringAlignment.Center;

for (int i = 0; i <= Polygons.Length - 1; i++)

{

TextSymbol[] TextSymbols = (TextSymbol[])TextSymbolArrays[i];

for (int j = 0; j <= Polygons[i].Parts.Length - 1; j++)

{

for (int k = 0; k <= TextSymbols.Length - 1; k++)

{

g.DrawString(TextSymbols[k].TextValue, TextSymbols[k].Font, TextSymbols[k].Brush, Polygons[i].Parts[j].Centroid.X + TextSymbols[k].XOffset, Polygons[i].Parts[j].Centroid.Y + TextSymbols[k].YOffset, Format);

}

}

}

}

 

 

 

public void DrawLabels(Graphics g, Array[] TextSymbolArrays, Array[] SymbolArrays, PointF[] Points, ref SimplePolygonF[] LabeledAreas, Int32 CanvasWidth, Int32 CanvasHeight)

{

// This routine left blank intentionally.

}

 

public void DrawLabels(Graphics g, Array[] TextSymbolArrays, Array[] SymbolArrays, MultiPointF[] MultiPoints, ref SimplePolygonF[] LabeledAreas, Int32 CanvasWidth, Int32 CanvasHeight)

{

// This routine left blank intentionally.

}

 

public void DrawLabels(Graphics g, Array[] TextSymbolArrays, Array[] SymbolArrays, MultiLineF[] MultiLines, ref SimplePolygonF[] LabeledAreas, Int32 CanvasWidth, Int32 CanvasHeight)

{

// This routine left blank intentionally.

}

} 

VB.NET

' Class declaration

Public Class CustomLabeler

Implements MapSuite.ILabeler

 

' DrawLabels routine

Public Sub DrawLabels(ByVal g As Graphics, ByVal TextSymbolArrays As Array(), ByVal SymbolArray As Array(), ByVal Polygons As MapSuite.Geometry.PolygonF(), ByRef LabeledAreas As SimplePolygonF(), ByVal CanvasWidth As Integer, ByVal CanvasHeight As Integer) Implements ILabeler.DrawLabels

' Drawing labels for polygons

Dim Format As New StringFormat()

Format.Alignment = StringAlignment.Center

For i As Integer = 0 To Polygons.Length - 1

Dim TextSymbols As TextSymbol() = DirectCast(TextSymbolArrays(i), TextSymbol())

For j As Integer = 0 To Polygons(i).Parts.Length - 1

For k As Integer = 0 To TextSymbols.Length - 1

g.DrawString(TextSymbols(k).TextValue, TextSymbols(k).Font, TextSymbols(k).Brush, Polygons(i).Parts(j).Centroid.X + TextSymbols(k).XOffset, Polygons(i).Parts(j).Centroid.Y + TextSymbols(k).YOffset, Format)

Next

Next

Next

End Sub

 

 

 

Public Sub DrawLabels(ByVal g As Graphics, ByVal TextSymbolArrays As Array(), ByVal SymbolArrays As Array(), ByVal Points As PointF(), ByRef LabeledAreas As SimplePolygonF(), ByVal CanvasWidth As Int32, ByVal CanvasHeight As Int32) Implements ILabeler.DrawLabels

' This routine left blank intentionally.

End Sub

 

Public Sub DrawLabels(ByVal g As Graphics, ByVal TextSymbolArrays As Array(), ByVal SymbolArrays As Array(), ByVal MultiPoints As MultiPointF(), ByRef LabeledAreas As SimplePolygonF(), ByVal CanvasWidth As Int32, ByVal CanvasHeight As Int32) Implements ILabeler.DrawLabels

' This routine left blank intentionally.

End Sub

 

Public Sub DrawLabels(ByVal g As Graphics, ByVal TextSymbolArrays As Array(), ByVal SymbolArrays As Array(), ByVal MultiLines As MultiLineF(), ByRef LabeledAreas As SimplePolygonF(), ByVal CanvasWidth As Int32, ByVal CanvasHeight As Int32) Implements ILabeler.DrawLabels

' This routine left blank intentionally.

End Sub

End Class  

Now, to use your custom labeler, you just need to create it and plug it in. Like the following:

C#

CustomLabeler cl = new CustomLabeler();
thld.LabelerPlugin = cl; // this assumes you have a zoomlevel object declared as thld

VB.NET

Dim cl As New CustomLabeler()
thld.LabelerPlugin = cl '-- this assumes you have a zoomlevel object declared as thld 

Back to Top

Can I change the data in a shape file, and if so, how?

Yes, you can. To delete shapes in the file, use the Layer.DeleteShape method which takes in a record number. If you want to change the data in a shape file, first you must call Layer.BeginEdit and then follow that with either Layer.CommitEdit or Layer.RollbackEdit. Between calling BeingEdit and CommitEdit or RollbackEdit you can call Layer.DeleteShape, Layer.AddShape, or Layer.UpdateShape depending on whether you want to do a delete, insert, or an update. The Layer sample named "Edit Shape File" is the sample that best illustrates this but below you will see some code that will help you.

C#

// Insert a new shape
private void mMapEngine_FinishedTrackShape(MapSuite.Geometry.BaseShape Shape)
{
mMapEngine.Layers[0].BeginEdit();

mMapEngine.Layers[0].AddShape(Shape);

mMapEngine.Layers[0].CommitEdit();
}

// Update an existing shape
private void Map1_FinishedTrackShape(MapSuite.Geometry.BaseShape Shape)
{
mMapEngine.Layers[0].BeginEdit();

mMapEngine.Layers[0].UpdateShape(Convert.ToInt32(lblRecordNumber.Text), Shape);

mMapEngine.Layers[0].CommitEdit();
}

// Delete an existing shape
mMapEngine.Layers[0].BeginEdit();

mMapEngine.Layers[0].DeleteShape(Convert.ToInt32(lblRecordNumber.Text));

mMapEngine.Layers[0].CommitEdit();

VB.NET

' Insert a new shape

Private Sub Map1_FinishedTrackShape(ByVal Shape As MapSuite.Geometry.BaseShape)

mMapEngine.Layers(0).BeginEdit()

mMapEngine.Layers(0).AddShape(Shape)

mMapEngine.Layers(0).CommitEdit()

End Sub

 

' Update an existing shape

Private Sub Map1_FinishedTrackShape(ByVal Shape As MapSuite.Geometry.BaseShape)

mMapEngine.Layers(0).BeginEdit()

mMapEngine.Layers(0).UpdateShape(Convert.ToInt32(lblRecordNumber.Text), Shape)

mMapEngine.Layers(0).CommitEdit()

End Sub

'-- Delete an existing shape
mMapEngine.Layers(0).BeginEdit()

mMapEngine.Layers(0).DeleteShape(Convert.ToInt32(lblRecordNumber.Text))

mMapEngine.Layers(0).CommitEdit() 

Back to Top

How can I stop one or more map shapes from being printed while printing the map?

The easiest way would be to set each map shape's Active property to false. If Active is true then the map shape will print, otherwise it will not. You can use this to stop just a few map shapes from printing or you could loop through the collection and stop them all from printing. The following code should help make it clear for you.

C#

// User clicks on something to trigger the printing of the map

// Before printing
mMapEngine.MapShapes[0].Active = false;

// Print map 

VB.NET

'-- User clicks on something to trigger the printing of the map

' Before printing

Map1.MapShapes.Item(0).Active = False 

' Print map

Now, the first map shape will not show in the print preview dialog. You could also put that one line inside of a loop and affect all the map shapes.

Back to Top

What do I need to do to distribute my application which uses Map Suite? How do I get all the dependencies on the destination computer?

In the full version of Map Suite, we include a merge module that can be included in your setup program. The merge module will install everything needed for Map Suite to run on that machine.

Back to Top

What vector and raster formats are supported by Map Suite?

For vector data, Map Suite supports ShapeFile format.
For raster imagery, Map Suite supports TIFF, GeoTIFF, MrSID, ECW, JPEG2000, BMP and JPEG.

Back to Top

How can I dynamically load controls using spatial queries?

A common task that Map Suite developers are faced with is dynamically loading user interface controls like a combo box based upon what is currently being displayed on the map. For example, you may have a map of the United States but only want to show the name of the states that are currently being displayed. The code below will show you how to do a spatial query using the Map1.CurrentExtent property which will only return the states that are currently shown on the map. Typically the best place to put this code is inside the Map1_CurrentExtentChanged event handler; this way, every time the map extent changes the control will be updated.

C#

//Add the following code to the Map1_CurrentExtentChanged event handler

if (mMapEngine.Layers["states"] != null)

{

// Build Up a Rectangle based upon the Map's current extent

StraightRectangle MapExtent = new StraightRectangle(mCurrentExtent);

int[] RecordIDs = null;

//Get the RecordID's for the states that are currently within the Map's extent

RecordIDs = mMapEngine.Layers["states"].SpatialQuery(MapExtent, SpatialQueryContainment.Containing);

DataTable CurrentStates = null;

//Get a Datatable containing information for the states that are visible

CurrentStates = mMapEngine.Layers["states"].DataQuery(RecordIDs, false);

//Bind the Datatable to the combo box

this.cboStates.DataSource = CurrentStates;

this.cboStates.ValueMember = "STATE_NAME";

} 

VB.NET

'Add the following code to the Map1_CurrentExtentChanged event handler

If mMapEngine.Layers("states") IsNot Nothing Then

' Build Up a Rectangle based upon the Map's current extent

Dim MapExtent As New StraightRectangle(mCurrentExtent)

Dim RecordIDs As Integer() = Nothing

'Get the RecordID's for the states that are currently within the Map's extent

RecordIDs = mMapEngine.Layers("states").SpatialQuery(MapExtent, SpatialQueryContainment.Containing)

Dim CurrentStates As DataTable = Nothing

'Get a Datatable containing information for the states that are visible

CurrentStates = mMapEngine.Layers("states").DataQuery(RecordIDs, False)

'Bind the Datatable to the combo box

Me.cboStates.DataSource = CurrentStates

Me.cboStates.ValueMember = "STATE_NAME"

End If 

Back to Top

Is there a way to highlight map features based on a SQL query?

Yes. Using any of the Map Suite products you can easily highlight a particular map feature. In the code example below we have written a simple SQL query that will return a single state from the states shape file and color it red using the Selects method. Utilizing the Selects method off of the Layer object is a quick and easy way to highlight one or many features on the map. To test this functionality out all you need to do is add the code below into the Load routine within the LayerInfoApp sample application (Note: You will need to add this code before the DrawMap() line).

C#

int[] RecordIDs;

 

//Retrieve the record numbers for the state(s) you want to highlight

RecordIDs = mMapEngine.Layers["states"].SQLQuery("Select * From States Where State_Name = 'Kansas'", "RecID");

 

//Highlight the state by using the selects method

mMapEngine.Layers["states"].Selects(RecordIDs);

 

//Define what color the selected states should show up as

AreaSymbol RedStateSymbol = new AreaSymbol(new SolidBrush(Color.Red));

 

mMapEngine.Layers["states"].SelectSymbols.Add(RedStateSymbol); 

VB.NET

Dim RecordIDs As Integer()

 

'Retrieve the record numbers for the state(s) you want to highlight

RecordIDs = mMapEngine.Layers("states").SQLQuery("Select * From States Where State_Name = 'Kansas'", "RecID")

 

'Highlight the state by using the selects method

mMapEngine.Layers("states").Selects(RecordIDs)

 

'Define what color the selected states should show up as

Dim RedStateSymbol As New AreaSymbol(New SolidBrush(Color.Red))

 

mMapEngine.Layers("states").SelectSymbols.Add(RedStateSymbol) 

Back to Top

How can I add satellite and aerial imagery to my project?

Using the ImageLayer Class you can add images in MrSid, ECW, TIFF, BMP, JPEG2000, or JPEG formats. Below we have written code that loads the image layer, sets the zoomLevel for the SymbolRenderer, and adds roads pulled from a shape file.

C#

'Load Image
ImageLayer imageLayer = new ImageLayer(@"..\..\sampledata\usa\unionspring\doqq_cir_unionsprg_ny.tif");

 

'Setup Road Layer

Layer roadsLayer = new Layer(@"..\..\sampledata\usa\unionspring\unionspringroads.shp", true);

roadsLayer.ZoomLevel01.GeoStyle = GeoLineStyles.GetSimpleLineStyle(GeoColor.KnownColors.LightGoldenrodYellow, 4, GeoColor.KnownColors.Black, 5);

roadsLayer.ZoomLevel01.GeoTextStyle = GeoTextStyles.GetMaskTextStyle("Name", "Arail", 8, GeoFontStyle.Bold, GeoColor.KnownColors.Black, GeoColor.KnownColors.LightGoldenrodYellow, 9, 0);

roadsLayer.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.ZoomLevel05;

 

mMapEngine.ImageLayers.Add(imageLayer);

mMapEngine.Layers.Add(roadsLayer);

 

mCurrentExtent = mMapEngine.ImageLayers[0].Extent ;

 

Bitmap bitMap = new Bitmap(PictureBox1.Width, PictureBox1.Height);

Graphics g = Graphics.FromImage(bitMap);

 

mMapEngine.GetMap(g, mCurrentExtent, bitMap.Width, bitMap.Height, MapLengthUnits.metres, 0);

 

g.Dispose();

VB.NET

'Load Image

Dim imageLayer As New ImageLayer("..\..\sampledata\usa\unionspring\doqq_cir_unionsprg_ny.tif")

 

'Setup Road Layer

Dim roadsLayer As New Layer("..\..\sampledata\usa\unionspring\unionspringroads.shp", True)

roadsLayer.ZoomLevel01.GeoStyle = GeoLineStyles.GetSimpleLineStyle(GeoColor.KnownColors.LightGoldenrodYellow, 4, GeoColor.KnownColors.Black, 5)

roadsLayer.ZoomLevel01.GeoTextStyle = GeoTextStyles.GetMaskTextStyle("Name", "Arail", 8, GeoFontStyle.Bold, GeoColor.KnownColors.Black, GeoColor.KnownColors.LightGoldenrodYellow, _

9, 0)

roadsLayer.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.ZoomLevel05

 

mMapEngine.ImageLayers.Add(imageLayer)

mMapEngine.Layers.Add(roadsLayer)

 

mCurrentExtent = mMapEngine.ImageLayers(0).Extent

 

Dim bitMap As New Bitmap(PictureBox1.Width, PictureBox1.Height)

Dim g As Graphics = Graphics.FromImage(bitMap)

 

mMapEngine.GetMap(g, mCurrentExtent, bitMap.Width, bitMap.Height, MapLengthUnits.metres, 0)

 

g.Dispose() 

Some tips on using ImageLayers:

  1. Make sure that your vector layer is in the same projection as your image layer. This will ensure that the roads in your shape file match up with the roads in your image.
  2. ImageLayers use Upper and Lower Threshold properties to control the visibility of this layer.
  3. Image layers need to be georeferenced to show up correctly on the map. This geo referencing information is stored in a corresponding world file.
  4. Be sure to check out our ImageApp Sample Application to see additional ways to add images to your maps.

Back to Top

 

 

Do you need base maps? Click here to browse Map Suite Dataset Plugins.

Download Free Trial

Download Free Trial

Try Map Suite free for 60 days.

View QuickStart Guides

View QuickStart Guides

Get started fast with Map Suite.

Try Online GIS Demo

Try Online GIS Demo

Sample Map Suite GIS applications.

Take The Tour

Take The Tour

Watch Map Suite video demos.

Buy Now

Buy Now

Purchase this product online.

Do More With Map Suite

Introducing the Map Suite World Map Kit Beta

Map Suite 3.0 developers now have an exciting new way to instantly add gorgeous maps of the world to their applications - with the all-new, just-released Map Suite World Map Kit Beta.

Map Suite Services Edition Beta 1 Is Here

Developing with Map Suite just got more exciting! Today I'm proud to announce the release of Map Suite Services Edition Beta 1, the first entry in our Map Suite 3.0 family of next-generation GIS software development tools for .NET.
Customer Testimonial: Alan Gould, President and CEO, www.westlakesoftware.com