Today, "We" released a new updated version of the Virtual Earth JavaScript Intellisense Helper that is updated to support the brand new Virtual Earth v6.2. You can learn more about what's new in Virtual Earth v6.2 here: http://blogs.msdn.com/virtualearth/archive/2008/09/24/announcing-the-virtual-earth-web-service-and-virtual-earth-map-control-6-2.aspx
It appears that Mark beat me to blogging this release (which makes sense since he's the one that posted the final ZIP of the release): http://blogs.msdn.com/devkeydet/archive/2008/09/30/released-virtual-earth-javascript-intellisense-helper-for-6-2.aspx
And, Thanks for the props Mark!
In case you aren't familiar with what the "Virtual Earth JavaScript Intellisense Helper" is:
"The purpose of this project is to fully enable JavaScript Intellisense for the Virtual Earth Map Control inside of Visual Studio 2008.
Creating Microsoft Virtual Earth mashups and applications just got a whole lot easier. This JavaScript library enables Intellisense for the Microsoft Virtual Earth 6.2 (current release) AJAX control in Visual Studio 2008"

Be the first to rate this post - Currently 0/5 Stars.
- 1
- 2
- 3
- 4
- 5
Today, I found an article on MSDN that covers how to perform a polygon search to determine if a given Lat/Long point is within a given Polygon.
I copied the logic for searching within the Polygon and made it more reusable than what is posted in the MSDN article, so I thought I'd post it here.
if (GeoHelper == undefined)
var GeoHelper = {};
GeoHelper.IsInPolygon=function(points,latlong)
{
// This code adapted from the following URL:
// http://msdn.microsoft.com/en-us/library/cc451895.aspx
var i;
var j=points.length-1;
var inPoly=false;
var lat = latlong.Latitude;
var lon = latlong.Longitude;
for (i=0; i<points.length; i++)
{
if (points[i].Longitude<lon && points[j].Longitude>=lon || points[j].Longitude<lon && points[i].Longitude>=lon)
{
if (points[i].Latitude+(lon-points[i].Longitude)/(points[j].Longitude-points[i].Longitude)*(points[j].Latitude-points[i].Latitude)<lat)
{
inPoly=!inPoly;
}
}
j=i;
}
return inPoly;
};
The usage of the IsInPolygon method is fairly simple, the first parameter is an array of VELatLong point objects that make up the Polygon, and the second is the VELatLong point object you want to test to see if it is located within the Polygon. Then the method simply returns True if it's within the Polygon, and False if it's not.
Also, this code would be very easily converted to C# or VB.NET if you need to perform the search within your server-side code.
Here's a full code sample demonstrating this. This sample allows you to click on the map, and when you click it checks to see if the point you clicked is within the polygon, and it displays an alert box telling you if it is or not.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title></title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <script type="text/javascript" src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.1"></script> <script type="text/javascript"> var map = null; var polygon = null;
function GetMap() { map = new VEMap('myMap'); map.LoadMap();
//Plot Polygon var points = new Array(new VELatLong(43.64486433588385, -79.3791389465332), new VELatLong(43.64508171979899, -79.3930435180664), new VELatLong(43.63682057801007, -79.38437461853027), new VELatLong(43.63946054004705, -79.36819553375244), new VELatLong(43.652720712083266, -79.37201499938965), new VELatLong(43.65793702655821, -79.39111232757568), new VELatLong(43.64927396999741, -79.37222957611084), new VELatLong(43.64486433588385, -79.3791389465332));
polygon = new VEShape(VEShapeType.Polygon, points); polygon.HideIcon(); map.AddShape(polygon); map.SetMapView(points);
//Add onclick handler map.AttachEvent("onclick", map_click); }
function map_click(eventArgs) { var latlong = map.PixelToLatLong(new VEPixel(eventArgs.mapX, eventArgs.mapY)); alert("Is Point Within Polyline:\n" + GeoHelper.IsInPolygon(polygon.GetPoints(), latlong)); }
if (GeoHelper == undefined) var GeoHelper = {};
GeoHelper.IsInPolygon=function(points,latlong) { // This code adapted from the following URL: // http://msdn.microsoft.com/en-us/library/cc451895.aspx
var i; var j=points.length-1; var inPoly=false; var lat = latlong.Latitude; var lon = latlong.Longitude;
for (i=0; i<points.length; i++) { if (points[i].Longitude<lon && points[j].Longitude>=lon || points[j].Longitude<lon && points[i].Longitude>=lon) { if (points[i].Latitude+(lon-points[i].Longitude)/(points[j].Longitude-points[i].Longitude)*(points[j].Latitude-points[i].Latitude)<lat) { inPoly=!inPoly; } } j=i; }
return inPoly; }; </script> </head> <body onload="GetMap();"> <div id='myMap' style="position: relative; width: 600px; height: 400px;"></div> </body> </html>
You can find the original MSDN article here:
http://msdn.microsoft.com/en-us/library/cc451895.aspx
Currently rated 4.0 by 1 people - Currently 4/5 Stars.
- 1
- 2
- 3
- 4
- 5
Now that we've Made Sense of the U.S. Census ZCTA ARC/INFO Ungenerate (ASCII) files in Part 1 of this series, we are ready to import the U.S Census ZCTA Zip Code data into a database. In Part 2, we'll create database tables and import the Zip Code Boundary data into those tables in a MS SQL 2005 database.
Create SQL 2005 Database Tables
First lets create a couple database tables to hold all the Zip Code boundary data. One table will hold the ZipCodes, the other will hold all the Boundary Points for each Zip Code.
The table scheme is as follows:
ZipCode
ID - uniqueidentifier
ZipCode - char(5)
ZipCodeBoundary
ID - uniqueidentifier
ZipCodeID - uniqueidentifier
IslandID - int
Latitude - float
Longitude - float
SortOrder - int
Here's a couple things to not about the ZipCodeBoundary talble:
- The IslandID field numbers each "island" or "zone" for that spefic zipcode's boundary. An island is an area within the zipcode that is omitted from the zipcode, or an island of land that is to be included within the zipcode that doens't physically thouch the main part of the boundary. The main boundary is going to have an IslandID value of 0 (zero).
- The SortOrder field numbers each boundary row in the order they appeared in the ARC/INFO Ungenerate (ASCII) file.
Here's the SQL code for creating these tables. For this article, I created these tables in a database named ZipCodeBoundaries.
USE [ZipCodeBoundaries]
GO
/****** Object: Table [dbo].[ZipCode] Script Date: 06/24/2008 15:40:28 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[ZipCode](
[ID] [uniqueidentifier] NOT NULL,
[ZipCode] [char](5) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
CONSTRAINT [PK_ZipCode] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
/****** Object: Table [dbo].[ZipCodeBoundary] Script Date: 06/24/2008 15:40:43 ******/
CREATE TABLE [dbo].[ZipCodeBoundary](
[ID] [uniqueidentifier] NOT NULL,
[ZipCodeID] [uniqueidentifier] NOT NULL,
[IslandID] [int] NULL,
[Latitude] [float] NULL,
[Longitude] [float] NULL,
[SortOrder] [int] NULL,
CONSTRAINT [PK_ZipCodeBoundary] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
Import Data Into Database Tables
To make things easier, I wrote a small utility that reads in the "a.dat.csv" and ".dat.csv" files generated in Part 1 of this series and imports the data into the table defined above. One thing to note when importing the data from these file (and the original ARC/INFO Ungenerate (ASCII) files) is that each set of files starts numbering the ZipCodes at 1. So when importing into the database we much give each Zip Code a unique ID (in this article I'm using GUID's for this) and setting that ID correctly for each of the Zip Code Boundary Points.
Download the Import Utility:
ImportARCINFOASCIIToSql05Database.zip (15.18 kb)
Remember, that when running this utility, it can take awhile to import ALL the ZipCode Boundary data for the entire country.
Note, this example utility has the connection string hard coded in the Form1.cs code file. Don't forget to change it to point to your database, unless you create your database on the local SQL Express instance and name it "ZipCodeBoundaries" like I do in this article.
Prev Part: Part 1 - Making sense of U.S. Census ZCTA ARC/INFO Ungenerate (ASCII) files
Next Part: Part 3 - Plotting Zip Code Boundary Data on a Map
Note: the next part of this series is not written yet, when I post it on the blog, I'll also update this part to link to Part 3.
Currently rated 5.0 by 1 people - Currently 5/5 Stars.
- 1
- 2
- 3
- 4
- 5
One question that I get fairly oftern is "How do I plot Zip Code boundaries on a map?". Well, the answer isn't simple, well at least it hasn't been. So, I've decided to write a series of articles going through the steps needed to obtain Zip Code boundary data, makes sense of it and plot it on a map. I'm not sure how many parts this series will be, but it'll probably be at least 3.
Where do I get Zip Cod Boundary Data From?
There are a number of campanies that sell geocode data that includes Zip Code Boundaries and many more things. But, if all you want are the Zip Code boundaries, it so happens that you can download this data completely free from the U.S. Census Bureau website. Zip Code Boundary data is actually one of the many different data sets available from the U.S. Census Bureau.
The data I'll focus on here is the Census 2000 5-Digit ZIP Code Tabulation Areas (ZCTAs) in ARC/INFO Ungenerate (ASCII) format. Even though these files are in their own "special" format, described here, they are still just plain ASCII and easily converted into CSV files to be imported into a database.
What's this ARC/INFO Ungenerate (ASCII) file format?
Ok, now that you've downloaded the Zip Code Boundary data in ARC/INFO Ungenerate (ASCII) format, it's time to make sense of this "special" file format they are in. Since the file format is in ASCII it is simple to make sense of.
Here's a couple snippets of data from each of the files that each .ZIP file you downloaded contains:
Files ending in "a.dat":
1
"356HH"
"356HH"
"Z5"
"5-Digit ZCTA"
2
"35677"
"35677"
"Z5"
"5-Digit ZCTA"
Files ending in ".dat":
1 -0.874385997915983E+02 0.347957138950617E+02
-0.881816728501744E+02 0.350078088730874E+02
-0.881819180000000E+02 0.349990240000000E+02
-0.881772430000000E+02 0.349917870000000E+02
-0.881751840000000E+02 0.349895430000000E+02
-0.881682580000000E+02 0.349777710000000E+02
The files that end in "a.dat" contain the zip codes and some other info along with an ID used to reference them in the other file.
The files that end in ".dat" contain all the geocode points for each of the zip codes defined in the other file.
How do I convert it to CSV?
Well, you could look at the ARC/INFO Generate (ASCII) Metadata Cartographic Boundary File Format definition and write a parser that then saves in in a CSV format.
Or, you could just download and use the one I wrote for this article:
Download Conversion Utility: ARCINFOASCIItoCSVConverter.zip (11.90 kb)
To use this utility, just unzip the contents of all the Zip files you downloaded from the U.S. Census Bureau website into a single folder, and click the "Convert All Files in Folder" button to select that folder and automatically convert all the files in that folder to a CSV file format.
The resulting CSV files will look like the following examples:
ZipID,FIPS CODES(S),NAME,LSAD,LSAD TRANSLATION
0, , , ,
1,356HH,356HH,Z5,5-Digit ZCTA
2,35677,35677,Z5,5-Digit ZCTA
3,35677,35677,Z5,5-Digit ZCTA
And...
ZipID,IslandId,LATITUDE,LONGITUDE,SortOrder
1,,-87.4385997915983,34.7957138950617,0
1,,-88.1816728501744,35.0078088730874,1
1,,-88.181918,34.999024,2
1,,-88.177243,34.991787,3
1,,-88.175184,34.989543,4
Now, you'll be able to able to easily import this data into a database, which brings us to the end of this part.
Reference Links:
See the following links for reference in addition to this article:
U.S. Census Bureau - Census 2000 5-Digit ZIP Code Tabulation Areas (ZCTAs) Cartographic Boundary Files
This is where you can download the U.S. Census Bureau's 5-Digit ZCTA files, specifically the ARC/INFO Ungenerate (ASCII) files used by the utility in this article.
ARC/INFO Generate (ASCII) Metadata Cartographic Boundary Files
This page contains the description of the file format used for the ARC/INFO Generate (ASCII) files.
Next Part: Part 2 - Import Zip Code (U.S. Census ZCTA) Data Into A Database
Currently rated 5.0 by 2 people - Currently 5/5 Stars.
- 1
- 2
- 3
- 4
- 5
The Virtual Earth team has officially launched their Virtual Earth Staging Environment. The staging environment allows you to access all the features of Virtual Earth (during development and testing) without incurring transaction costs against your production account.
How do I access the Virtual Earth Staging Environment?
Simple, just use the following url when you include the VE JavaScript Control in your page. Notice, the only change in the url is the "staging." in the beginning, otherwise the url is exactly the same.
<script type="text/javascript" src="http://staging.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.1"></script>
One thing to note about using the VE Staging environment is it doesn't work under SSL. If you need to test under SSL, and don't want to have the little "Yes/No" dialog show on each page load, then you'll need to test using the production url for now. I'm sure they'll fix this at some point, but we'll see.
Should I use the Virtual Earth Staging Environment?
You should use the Virtual Earth Staging Environment if you don't want to have the map transactions used during testing to count towards the transactions you're billed for. Also, if you haven't entered into a service level agreement with Microsoft for Virtual Earth, then you do not need to worry about the Staging environment, since you aren't being billed anyway.
For more information on using the Virtual Earth Staging Environment with Implementing Customer Identification see the "Virtual Earth: Implementing Customer Identification" article in MSDN.
Be the first to rate this post - Currently 0/5 Stars.
- 1
- 2
- 3
- 4
- 5
Today, I released Web.Maps.VE v2.0!! I had originally planned to release it on June 30th, but was able to reach that goal about 2 weeks early, so here we are. Web.Maps.VE v2.0 builds on top of the previous v1.0 release, and adds many new features.
If you aren't familiar with Web.Maps.VE, it is the industries first ASP.NET Virtual Earth Mapping Server Control. It enables you (the developer) to implement MS Virtual Earth mapping into your ASP.NET web applications by writing only server-side code; there is absolutely no javascript required. It has never been easier to implement MS Virtual Earth mapping.
Some of the key features in Web.Maps.VE v2.0 are:
-
Plot Pushpins, Polylines and Polygons with Multiple Shape Layer Support
-
Perform "Find" searches from Server-side ASP.NET code
-
Reverse Geocoding (via FindLocations) from Server-side ASP.NET code
-
Plot Multi-Point Driving (and Walking) Directions
-
Implemnt MS Virtual Earth mapping from within Server-side ASP.NET code; No JavaScript Required
-
Server-side Handling of Client-side Map Events (onclick, endzoom, endpan, etc.)
-
Ability to easily build Dynamic/Interactive style Map-based searches
-
Supports ASP.NET 3.5 and Visual Studio 2008 with Design-Time Support
There are many more features to Web.Maps.VE v2.0; go Download the FREE Trial to see for your self.
One dependency that v1.0 has, was it was tied to the ASP.NET AjaxControlToolkit since it utilized some of the base classes within that library. Well, v2.0 no longer has a dependency on the ASP.NET AjaxControlToolkit, so you no longer have to worry about keeping your application in sync with the version of the AjaxControlToolkit that Web.Maps.VE requires.
Another very important thing to mention; we have changed the licensing for Web.Maps.VE v2.0. Web.Maps.VE v2.0 now uses a "Per Developer" licensing model, instead of the "Per Website" licensing model that v1.0 used. The Web.Maps.VE v2.0 Single Developer License allows a single developer the ability to develop Web.Maps.VE functionality into any ASP.NET web application they build. The Web.Maps.VE v2.0 component DLL can then ben distributed with any software built using the Single Developer License. This allows you (an individual developer) to use Web.Maps.VE v2.0 in as many ASP.NET web applications as you would like.
Go check out Web.Maps.VE v2.0 here: http://simplovation.com/page/webmapsve.aspx
Also, if you've purchased a Web.Maps.VE v1.0 Single Website License prior to June 17th, 2008; then you may qualify for a 20% discount to upgrade to Web.Maps.VE v2.0 until August 31st, 2008. Please contact Simplovation for more information regarding this special offer for existing customers.
Be the first to rate this post - Currently 0/5 Stars.
- 1
- 2
- 3
- 4
- 5
Today, I released the 8th update (v1.00.08) release to the Simplovation Web.Maps.VE v1.0 ASP.NET AJAX Virtual Earth Mapping Server Control. This control has come along way since the initial (v1.00.00) release last October. It greatly simplifies the implementation of Virtual Earth into any ASP.NET web application by enabling full server-side (.net, C#, VB.NET) control of the map, while eliminating the need to write javascript/jscript. Unless of course you want to write javascript; in which case Web.Maps.VE has a full client-side javascript api that allows an unlimited number of customizations to be done.
I have also been working hard to meet the deadline of June 30th for the release of Web.Maps.VE v2.0. This release will greatly improve upon the v1.0 release by adding Shape Layer support, improved 3D map support, eliminating the dependency on the AjaxControlTookit, among other things.
Go check out Web.Maps.VE for FREE by downloading the Web.Maps.VE v1.0 FREE Developer / Trial License.
Be the first to rate this post - Currently 0/5 Stars.
- 1
- 2
- 3
- 4
- 5
One of the tricky things that you need to work around when programming Virtual Earth is the VEMap.GetCenter() method doesn't work when displaying the Birdseye or Oblique Map Style. I'm not exactly sure what the reasoning for this is, but this is one thing that I would like to see fixed in a future version. Luckily, there is an unsupported method of doing this.
The code shown below gets the center Lat/Long coordinate for the BirdseyeScene being shown, not the actual center of the Map. This isn't exaclty what we're looking for, but at least it gives us a better idea of the current position of the map than nothing.
Here's a full example page that demonstrates getting the Map's center Lat/Long "relatively" when in Birdseye or Oblique Map Style:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title></title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <script type="text/javascript" src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.1"></script> <script type="text/javascript"> var map = null; function GetMap() { map = new VEMap('myMap'); map.LoadMap();
map.SetCenterAndZoom(new VELatLong(41.8797864435218, -87.681884765625), 11); map.SetMapStyle(VEMapStyle.Birdseye); }
function GetCenterLatLong() { //Check if in Birdseye or Oblique Map Style if (map.GetMapStyle() == VEMapStyle.Birdseye || map.GetMapStyle() == VEMapStyle.BirdseyeHybrid) { //IN Birdseye or Oblique Map Style
//Get the BirdseyeScene being displayed var birdseyeScene = map.GetBirdseyeScene();
//Get approximate center coordinate of the map var x = birdseyeScene.GetWidth() / 2; var y = birdseyeScene.GetHeight() / 2;
// Get the Lat/Long var center = birdseyeScene.PixelToLatLong(new VEPixel(x,y), map.GetZoomLevel());
// Convert the BirdseyeScene LatLong to a normal LatLong we can use return (new _xy1).Decode(center); } else { // NOT in Birdseye or Oblique Map Style return map.GetCenter(); } }
function DisplayCenter() { var center = GetCenterLatLong(); alert("Latitude: " + center.Latitude + "\nLongitude: " + center.Longitude); } </script> </head> <body onload="GetMap();"> <input type="button" value="Get Center Lat/Lng" onclick="DisplayCenter();"/> <div id='myMap' style="position:relative; width:400px; height:400px;"></div> </body> </html>
Currently rated 4.0 by 3 people - Currently 4/5 Stars.
- 1
- 2
- 3
- 4
- 5
A couple weeks ago, while attending the Heros Happen Here launch event in Milwaukee, I ran into Larry Clarkin who is co-host of The Thirsty Developer, and we recorded The Virtual Earth Edition episode that he just released today. In the podcast, I talk about how I got into Virtual Earth development, and give a good overview of the Virtual Earth product, among other things VE related, including the Virtual Earth JavaScript Intellisense Helper and my Web.Maps.VE product.
Listen here: The Thirsty Developer 23: The Virtual Earth Edition
Currently rated 5.0 by 1 people - Currently 5/5 Stars.
- 1
- 2
- 3
- 4
- 5
A couple months ago I blogged about the fact that using Virtual Earth and ASP.NET AJAX together on the same page caused errors in Safari. There is good new to report back, the latest update to Virtual Earth has fixed this issue. In fact Virtual Earth v6.1 actually includes much better Safari support that previous versions; it actually works correctly in Safari. I found this to be especially helpful since I can now support Safari with my Web.Maps.VE product.
What's the catch? I can't work perfectly now can it. Well, as far as I can tell Virtual Earth works great. However, the code example in my post calling attention to the error actually still has a little bug in it. The bug is the calendar that is automatically shown on hover over by the AjaxControlToolkit CalendarExtender get hidden by the Map below the textbox. This is actually caused by a layering issue related to the z-index of the elements on the page. An easy way to fix this is to just set the z-index of the VEMap's DIV element to a lower value so all other elements on the page will be rendered over the top of it.
Here's the full example code showing example what I mean above:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> <%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="ajaxToolkit" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head id="Head1" runat="server"> <title>Untitled Page</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <script type="text/javascript" src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.1"></script> <script type="text/javascript"> var map = null; function GetMap() { map = new VEMap('myMap'); map.LoadMap(); } </script> </head> <body onload="GetMap();"> <form id="form1" runat="server"> <asp:ScriptManager runat="server" ID="ScriptManager1"></asp:ScriptManager> <div> <asp:TextBox runat="server" id="txtDate"></asp:TextBox> <ajaxToolkit:CalendarExtender runat="server" ID="CalendarExtender1" TargetControlID="txtDate"></ajaxToolkit:CalendarExtender> <br /><br /> <div id='myMap' style="position:relative; width:400px; height:400px; z-index: -100;"></div> </div> </form> </body> </html>
Be the first to rate this post - Currently 0/5 Stars.
- 1
- 2
- 3
- 4
- 5
|