Welcome to MSDN Blogs Sign in | Join | Help

Basic Math

When working with things that exist on the globe, there is a fair bit of basic math that complicates your life.  Let's start of with a mesh that you want to add to the Earth.  We recommend that you orient your mesh so that it is facing along the Y axis, Z is up, and X is to the right, as shown with this car.  While you can do your own thing, this will simplify using RollPitchYaw later, which is the most common way that we orient things locally.

    Recommended local coordinates.

Now the object needs to be placed on the Earth which involves transforming it from it's local space, onto the globe.  The globe is a WGS84 ellipsoid that is laid out as shown in this image.  Note that the Z axis points up through the North Pole, and the X axis points out through latitude\longitude 0,0 (just south of Ghana in the Atlantic).

      Structure of the globe

So if your object is placed on this globe and it has a local yaw of 0, it will be facing North.  If it has a local pitch of 0, it will be looking horizontally... approximately at the horizon.  If your local orientation remains the same, but the position of the object changes on the surface of the globe, the global orientation of the object will change.  To assist in the manipulation of position, local orientation, and global orientation, we provide the Microsoft.MapPoint.Rendering3D.Cameras.GeodeticViewpoint class.  This class automatically handles the conversions, for example: 

// Set up the viewpoint with a position and local orientation.
GeodeticViewpoint viewpoint = new GeodeticViewpoint();
viewpoint.Position.Location =
new LatLonAlt(33, -97, 10000); // Someplace over Dallas
viewpoint.LocalOrientation.RollPitchYaw =
new RollPitchYaw(0, 0, 90.0 * Constants.RadiansPerDegree);

// Ask for the global orientation.
LookAtLookUp globalOrientation = viewpoint.Orientation.LookAtLookUp;

Note that the local yaw is set to 90 degrees which will face West.  The reason is that RollPitchYaw represents a rotation around the Y, X, and Z axes respectively.  So a Yaw rotation is the left most diagram below.  This diagram holds for any use of Matrix4x4D.RotationX, Y, or Z, and can be useful in mentally visualizing how you're rotating in our coordinate space.

    Rotation

The GeodeticViewpoint class has a bunch of helper properties on it, for example you can adjust just the altitude on the viewpoint, and anything that depends on that change will cascade out:

viewpoint.Position.Altitude = 500;

Also, one of the things that using the viewpoint also saves you is that calculating the exact X,Y,Z coordinate from the latitude/longitude/altitude that you provided which is quite tricky since we use WGS84.  However GeodeticViewpoint makes that easy:

Vector3D coordinate = viewpoint.Position.Vector;

I've shown a lot of random tidbits above, and included diagrams from bits of "cheat sheet" that I made up for developers here.  If there are parts that don't make sense, feel free to comment.

Posted by Heptazane | 0 Comments
Filed under: , ,

Installing Plug-Ins

Some types of plug-ins feature special data or rendering, and are intended to be used with a particular website.  Others are intended to enhance the experience of all websites, and run every time a user runs VE3D.  Most of the samples given so far have been about the former, where the test html page references the plug-in you wish to load.  Today we’ll talk about the latter.

In addition, there is currently a limitation that plug-ins must be installed in the GAC in order to run.  This is true regardless of what category the plug-in falls under.  End users of a plug-in will need a way of installing the plug-in.  Fortunately writing an installer is easy with Visual Studio.

The first link contains the source code for the plug-in itself and the deployment project.  The plug-in is set up to run in a test page just like the others, but the intended way to use this solution is to build PlugInSetup.  That project will take the output of the plug-in project, add it to an MSI along with some appropriate verbiage, and a setup.exe bootstrapper to run the MSI.  Once those are built, the setup.exe and MSI combination can be distributed to end users.  In my case, I created a self-extracting zip archive – the output is the second link.  Visual Studio won’t do this directly, so use your favorite tool to create a nice single package for users.  This method doesn’t necessarily create the most elegant installer, and any installer package that has the same features could be used, but this one works and is easy to use.

The important parts of the PlugInSetup projects are the files to include and the various text messages to display.  Right click on the project name, and select View -> File System.  The file locations we’d like to install to are shown.  In order to run an automatically-running plug-in, we must install to a special location under VE3D’s install path, as seen here.  A plug-in that loads on demand, as from a custom website, would install to its own Program Files directory.  For this plug-in, there are no user-specific resources so all users will be able to use the plug-in when they run VE3D.

Adding output to Program Files

We also must add our plug-in to the Global Assembly Cache.  This can be seen below.

Adding output to the GAC.

New files may be added to both by right clicking in the right-hand side of the main view, and new locations may be added by right-clicking in the left-hand side.

We may also modify various items like author name and contact info by clicking on the PlugInSetup project and looking at the properties page.

Deployment Project Properties page

The plug-in itself is a simple project to remember camera viewpoints and fly back to them when the user presses a key.  It has no UI elements except for notifications on error, which is desirable for a plug-in that will always be run.  Ideally, some form of instruction for the user would appear on startup or during the install but for now we are keeping it simple.  To save a viewpoint, hold shift and then press a number key from 1 to 4.  To return to that viewpoint, even after restarting the app, press the same number key again, this time without holding shift.  To reset all the views, press 0.

The project uses the bindings system with a config file, meaning that end users may change the keys used by editing the ShortcutBindings.xml file (see the code for comments on the location of this file).  It also uses IsolatedStorage for safe persistence of data, unique to the plug-in and user (so different users may have different saved views).  The code has comments that hopefully explain what's going on, but some of it, bindings especially, will be a topic for a future post.

 

Enjoy!

Posted by NikolaiF | 1 Comments

Creating the most basic Windows Form

The samples that can be downloaded below demonstrate creating a basic Windows Application with a VE3D control on it (SimpleForm), however, I wanted to go over the most basic steps.  The sample does not use the Toolbox, but I will.

Step 1: Make sure the VE3D control is installed by visiting http://maps.live.com and switching to 3D. 

Step 2: Select Tools->Choose Toolbox Items... 

Step 3: Make sure GlobeControl is checked in .NET Framework Components tab.  The version should be 2.0.711.13001.  GlobeControl should now show up in your Toolbox under the General section with a gear icon next to it.

Choose Toobox Items dialog

Step 4: Create a new C# Windows Application in Visual Studio 2005.

Step 5: Select GlobeControl from your Toolbox and drop it onto your form.  It should show up with just a big, grey dot in the middle and "GlobeControl" written across it.  This is just the designer view.  If you run the application at this point, you'll see the globe in 3D, but only with the outer most model and if you zoom in you'll just get fuzzy green.  The reason is that we haven't set up any data sources yet, so...

Step 6: Make sure your form is selected (not the GlobeControl) and add a Load event (select the lightening bolt for events in the Properties pane, find Load and double click on it).  Make sure it looks like this:

private void Form1_Load(object sender, EventArgs e)
{
    this.globeControl1.Host.DataSources.Add(new DataSourceLayerData("Elevation", "Elevation", @"http://maps.live.com//Manifests/HD.xml", DataSourceUsage.ElevationMap));
    this.globeControl1.Host.DataSources.Add(new DataSourceLayerData("Texture", "Texture", @"http://maps.live.com//Manifests/HT.xml", DataSourceUsage.TextureMap));
    this.globeControl1.Host.DataSources.Add(new DataSourceLayerData("Models", "Models", @"http://maps.live.com//Manifests/MO.xml", DataSourceUsage.Model));
}

Step 7: To use the DataSource classes, you'll need to right-click on your project's references and select Add Reference..., select the Browse tab and browse to "C:\Program Files\Virtual Earth 3D".  Select "Microsoft.MapPoint.Data" and "Microsoft.MapPoint.Rendering3D.Utility" and hit OK.

Step 8: Run your application and enjoy!

Definitely look at the samples for more goodness, but these are the basic steps to get started.

Geometry

The first thing that most people want to do when playing with the 3D control is add some stuff to the world.  The most straightforward way to do this is via the Geometry Manager, accessible from Host.Geometry.  You can modify any of the samples to contain this code, most easily in the Activate function of a plug-in or OnLoad for SimpleForm.

      Host.Geometry.AddGeometry(new PushpinGeometry(

            "My Layer", "My Id",

            LatLonAlt.CreateUsingDegrees(-47.6435, 112.1422, 100.0),

            PushpinInfo.Default));

This creates a default pin on top of Microsoft Building 116 in Redmond, WA, just in case you were wondering where that is.  The first two parameters are just identifiers.  You can use Layers to group items together, but it's not required.  The two strings together just have to be unique.  The third parameter is the position of the pin in Latitude, Longitude, Altitude.  Here we’re using degrees in WGS84, and meters for the altitude.

Let me digress on units for a moment.  Notice that latitude, which is the “Y” component of the coordinate, comes first.  This is a long-standing convention when specifying geographic coordinates, but for our purposes is somewhat arbitrary.  In other contexts, for example when we use a Coordinate2D struct, which is a more general-use structure not tied to a specific coordinate system, we’ll follow the mathematical convention of “X” first.  Also, values of latitude and longitude are technically angles (from the equator and around the polar axis, respectively).  When dealing with angles in computers it is convenient to store them as radians, which is how most trigonometric functions deal with them.  However, degrees are usually easier to think about.  So here we create the structure explicitly in degrees to reduce confusion.  If you ever have trouble with your pushpin not appearing, the first thing to check is the order of your values and their units.  We use meters for distances and altitudes, but the exact meaning of altitude can change depending on what AltitudeMode you are associating with the geometry.

Back to the pushpin, next we’ll want to change how it appears.  If you pull the PushpinInfo.Default object into a local variable, you can then modify the various provided values, leaving others as they are.

      PushpinInfo info = PushpinInfo.Default;

      info.Resource = http://kristoffer.members.winisp.net/VE3D/jewel.png;

      info.OrientationMode = PushpinOrientationMode.UseProvided;

      info.Orientation = new Orientation(new RollPitchYaw(

            0.0,

            20 * Constants.RadiansPerDegree,

            45 * Constants.RadiansPerDegree));

      Host.Geometry.AddGeometry(new PushpinGeometry(

            "My Layer", "My Id",

            LatLonAlt.CreateUsingDegrees(47.6435, -122.1422, 10.0),

            info));

 

In this case we’ve added a pretty logo over the same building rather than using the default orange pin, and told it to use a specific orientation instead of always facing the camera.  Roll/Pitch/Yaw (RPY) is in degrees, but we can convert using some constants.  Think of the image as a face, with the nose pointing straight out of the middle of it.  If you supply a RPY of (0, 0, 0) the face will point north, toward the horizon, with the head level.  Rolling will be like tilting the head sideways towards the shoulders, pitch is like looking up and down, and yaw is looking side to side.  In this case, we are looking slightly up and to the northwest.  You can combine the values with values from the camera to get interesting effects by setting OrientationMode.  AltitudeMode is set here, to control the exact meaning of the altitude component of its position.

 

The two other basic types of geometry are PolylineGeometry and PolygonGeometry.  Their setup is similar, except that you will provide arrays of LatLonAlt values.  There are also two distinct categories of each, those that are drawn on the ground and those drawn in the air.

 

Host.Geometry.AddGeometry(new PolygonGeometry(

            "My Layer", "My Poly",

            null,

            new LatLonAlt[] {

                  LatLonAlt.CreateUsingDegrees(47.6435, -122.1422, 0.0),

                  LatLonAlt.CreateUsingDegrees(47.645, -122.1422, 0.0),

                  LatLonAlt.CreateUsingDegrees(47.645, -122.1412, 0.0),

                  LatLonAlt.CreateUsingDegrees(47.6435, -122.1412, 0.0) },

            PolygonGeometry.PolygonFormat.Polygon2D,

            PolyInfo.DefaultPolyline));

 

The Format parameter specifies what type they should be, and altitude values will be ignored for 2D versions (note:  LineList2D is currently not supported, but the rest all have their uses).  The third parameter here is a “tag”, which is something that can be used when your user is interacting with your objects via the mouse.  In the Geometry sample you can see some of these ideas (and a few other things) in play.

Adding a Virtual Earth 3D Plug-in to your webpage

Want to try custom code for the 3D view of Virtual Earth?  This is the place to find out how!

 

What do I need?

·         Virtual Earth 3D installed.  Navigate to maps.live.com, click the 3D button, and follow the upgrade/install steps. 

·         Visual Studio 2005 or higher and some c# coding skills (any .NET language actually, but samples will be in C#).

·         This package. 

 

If you do not have Visual Studio installed, you can download a free version of Visual Studio 2008 here.  See notes at the end of the post for details.

 

Extract the samples zip to c:\Samples (or any other directory, but you'll have to fix up some paths in the projects).  There's a Readme, but you should be able to just open the sln in Visual Studio, set one of the projects to the Startup project, and hit F5.  For this post, we'll just talk about the basics of how the plug-in will be loaded.

 

Try building and launching the project SimpleObjectPlacement.

 

 Selecting the Startup Project

 

By default, you'll get an IE window with a script warning.  This only happens because we're loading the html off the local drive, and will not happen if we point to a web server.

 

Script warning in IE

 

You can change startup behavior by modifying the values in the Debug pane of the project.

 

Debug pane of the project properties

 

Once there you should see the globe, and after a moment it will zoom to off the coast of Africa to see a floating cube.

 

Yay, a colored cube!

 

So what happened?  First, we have a very simple webpage that loads the JavaScript SDK, and then extracts the 3D control from it to do some special loading.  This is an unsupported thing to do (well heck, everything in these samples is unsupported, but that doesn’t mean it won’t work), but we need to get at the Events and LoadPlugInDll methods.

 

    map = new VEMap('myMap');

    map.SetDashboardSize(VEDashboardSize.Normal); 

    map.LoadMap(null, 2, 'a', false, VEMapMode.Mode3D);

    control3D = map.vemapcontrol.Get3DControl();

    control3D.AttachEvent("OnPlugInLoaded", "On3DPlugInLoaded");

    control3D.AttachEvent("OnPlugInActivated", "On3DPlugInActivated");

    control3D.AttachEvent("OnPlugInDeactivated", "On3DPlugInDeactivated");

    control3D.LoadPlugInDll("C:\\Samples\\SimpleObjectPlacement\\bin\\Debug\\SimpleObjectPlacement.dll");

 

Events are just callbacks when certain things happen.  In this case, when a plug-in is finished loading the SDK will try to call a function called "On3DPlugInLoaded".  It has to be this way because the LoadPlugInDll method is asynchronous -- otherwise we'd have to sit and wait for loading to complete, causing a negative user experience.  But you don't have to worry much about this, just know that you can listen to events and you'll be called when things happen.  You can also fire your own events, which we'll get to later.  In this case, if you look at the handler you'll see when we finish loading the plug-in we'll activate it.  We could do more, but this is the minimum.

 

You can specify a plug-in to load in two ways.  First is like this, with a local file path.  Second is by specifying the fully qualified name.  Either method requires that the plug-in be installed in the GAC, which is an unfortunate security limitation that we hope to relax in the future.  You can get installed into the GAC by using utilities that come with VS, or by writing an MSI installer.  We'll get into more on that later.  All the samples here install their output into the GAC as a post-build step to help you get past these details.

 

When the plug-in is loaded, then we start executing the C# code.  If you put breakpoints in SimpleObjectPlugIn.cs, you'll see it gets a call to the constructor, and then one to the Activate function.  In a future post we'll walk through the details of what happens next, how the cube gets into the world, and why it changes color when you mouse over it.  In the meantime, try playing with the other samples.  Let us know what you think, and please enjoy.

 

Download Samples.zip

 

Notes on VS 2008 and VS 2008 Express:

If you use either of these, you'll have to run the solution upgrade wizard.  It should be painless, but you may encounter some of the following issues:

VS 2008 Full and Express:

If you get errors on build about gacutil and return code 3, you may need to update the path in the project pre- and post-build steps to "$(DevEnvDir)..\..\..\Microsoft SDKs\Windows\v6.0A\bin\gacutil".

VS 2008 Express:

A message about a property not supported.  This is related to the last point below, and can be ignored.

A message about Solution Items not supported (VS Express).  This is just the readme file and can be ignored (you can still read the readme by just navigating to c:\samples).

Express only builds to the Release bin path, so the html files (TestPage.htm) need to be updated such that the LoadPlugInDll call points to bin\\Release instead of bin\\Debug.

VS Express doesn't support debugging a different process than the one launched.  This is tricky because plug-ins run in the browser's process.  To run the plug-in samples you'll need to build the project, and then run the html file manually in your favorite browser.  However, you can debug a forms app as normal, so you can work around this by debugging your code inside the SimpleForm sample, and then copying to the plug-in.  We apologize for this inconvenience, but it was free after all ;)

 
Page view tracker