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?
- I would like to have more custom properties
(like a tag property) on a map shape object. How can I add my own
properties?
- How do I convert screen coordinates into
world coordinates?
- How do I convert world coordinates into
screen coordinates?
- I see a layer can have different zoomLevels.
What would I use this feature for?
- How can I get information about point or
feature from a dbf file?
- Once I have a record number, how can I get
the shape for that record?
- 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?
- 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.
- How can I use my own rendering logic when
the symbol representing an place's location is being drawn?
- 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.
- I see that a map can have multiple layers.
Why would I use multiple layers?
- How can I print a map?
- 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?
- What are map shapes and how can I use them?
- How can I define my own custom labeling
plug-in?
- Can I change the data in a shape file, and
if so, how?
- How can I stop one or more map shapes from
being printed while printing the map?
- 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?
- What vector and raster formats are
supported by Map Suite?
- How can I dynamically load controls using
spatial queries?
- Is there a way to highlight map features
based on a SQL query?
- How can I add satellite and aerial imagery
to my project?
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:
- 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.
- ImageLayers use Upper and Lower Threshold properties to
control the visibility of this layer.
- Image layers need to be georeferenced to show up correctly
on the map. This geo referencing information is stored in a corresponding
world file.
- Be sure to check out our ImageApp Sample Application to
see additional ways to add images to your maps.
Back to Top
|
|
Try Map Suite free for 60 days.
|
Get started fast with Map Suite.
|
Sample Map Suite GIS applications.
|
Watch Map Suite video demos.
|
Purchase this product online.
|
|