Writing your own method to transfer MicroStation data to Google Earth is relatively easy and straightforward. Google Earth reads in data from the KML format, a variety of XML, or from the KMZ format, which is simply a zipped KML file. All that is needed to export to either format is to call mdlKml_exportToFile(), which can be found in kmlexport.fdf along with MicroStation's other functions for dealing with Google Earth. This article offers a quick introduction to using mdlKml_exportToFile().
Step One: Basic export to Google Earth
First, we will create and initialize our IKmlCoordinateRemapper object. This object is used to translate between MicroStation UORs and the WGS84 coordinates that Google Earth uses. If the remapper cannot be initialized, the design file has not been geolocated and cannot be exported to Google Earth. Thus, it is a good idea to always make initializing the remapper one of the first steps in your application.
IKmlCoordinateRemapperP pRemapper;
if (SUCCESS != mdlKml_getRemapper (&pRemapper, MASTERFILE))
return;
Next, we load the user's default Google Earth export settings and grab a handle on the user's resource file.
KmlExportSettings settings;
mdlKml_getDefaultExportSettings (&settings);
RscFileHandle rscHandle;
mdlResource_openFile (&rscHandle, NULL, FALSE);
With that done, we get the user's currently selected MicroStation view to use as our Google Earth file's default view.
int viewToExport = mdlWindow_getSelectedViewIndex ();
Next, we define the filename and location for our Google Earth file. The filename used determines whether the Google Earth file is output as a compressed KMZ archive or an uncompressed KML file. KMZ is the recommended output format because the files are exponentially smaller and KMZ files can contain their associated raster data and link icons, making them more portable.
char const* fileName = "C:\\Example.kmz";
Finally, we define a name and description for our example file, then call mdlKml_exportToFile() with the values we have just defined. Do not concern yourself with the null value -- that is just a placeholder for the deprecated KmlExportStatistics object.
MSWChar const* wName = L"Example";
MSWChar const* wDescr = L"An example KMZ file."; mdlKml_exportToFile (fileName, wName, wDescr, NULL, MASTERFILE, &settings, pRemapper,
viewToExport, rscHandle);
After making this call, Example.kmz should be created and ready to go -- all that is left is to clean up after ourselves by freeing the remapper and resource file handle.
mdlKml_freeRemapper (&pRemapper);
mdlResource_closeFile (rscHandle);
Step Two: Creating a custom placemark provider
With the basics covered, we can now move on to the slightly more complex topic of creating custom Google Earth placemarks based on MicroStation element data. The IKmlElementPlacemarkProvider interface exists for this purpose. In order to use it, we only need to implement the ProvideElementPlacemark method and provide correct values for pName, pDescription, and pLocation. If any of the icon variables are left null, the default icon style will be used.
The following example implementation scans each element for Engineering Link information and if it is found, fills in the fields necessary to generate a placemark. It also uses Google Earth's capability to use custom icons for different placemarks.
/*===============================================================**//**
* @bsiclass BSI 04/06
+================+==============+==============+=============+=======*/
class ExamplePlacemarkProvider : public IKmlElementPlacemarkProvider
{
public:
/*---------------------------------------------------------------**//**
* @bsimethod BSI 04/06
+----------------+--------------+--------------+-------------+-------*/
virtual bool ProvideElementPlacemark
(
MSWChar* pName, /* <= Name for the new placemark */
MSWChar* pDescription, /* <= Description for the new placemark */
DPoint3d* pLocation, /* <= Placemark location in UORs */
int* pIconX, /* <= X coordinate for placemark icon */
int* pIconY, /* <= Y coordinate for placemark icon */
int* pIconWidth, /* <= Width of placemark icon */
int* pIconHeight, /* <= Height of placemark icon */
double* pIconScale, /* <= Scale of placemark icon and its label text */
char* pLinkIconFileName, /* <= Location of the icon file */
MSElementDescrP pElement /* => Current element */
)
{
char description[1024], url[1024], string[4096]; // Find an Engineering Link attached to the element.
if (mdlTag_extractURL (url,
description,
const_cast <MSElementP> (&pElement->el),
(pElement->h).dgnModelRef))
{
// Fills in the same name and target values for the new placemark as the
// Engineering Link.
sprintf (string, "<a href=\"%s\">%s</a>", url, description);
mdlCnv_convertMultibyteToUnicode (description, -1, pName, 1024);
mdlCnv_convertMultibyteToUnicode (string, -1, pDescription, 1024); // Gets the element's location in UORs.
DVector3d range;
mdlElement_extractRange (&range, &pElement->el);
mdlVec_addPoint (pLocation, &range.org, &range.end);
mdlVec_scale (pLocation, pLocation, .5); // Helper function to acquire icon information for the new placemark.
GetIcon (url, pIconX, pIconY, pIconWidth, pIconHeight, pIconScale,
pLinkIconFileName);
// Return true to inform the exporter that a placemark should be generated for
// this element.
return true;
}
// Return false to inform the exporter that a placemark should not be generated for
// this element.
return false;
}
/*---------------------------------------------------------------**//**
* @bsimethod BSI 04/06
+----------------+--------------+--------------+-------------+-------*/
void GetIcon
(
char* url, /* => Link URL */
int* pIconX, /* <= X coordinate for icon
Distance from left most edge in pixels */
int* pIconY, /* <= Y coordinate for icon
Distance from bottom most edge in pixels */
int* pIconWidth, /* <= Width of icon in pixels */
int* pIconHeight, /* <= Height of icon in pixels */
double* pIconScale, /* <= Scale of icon */
char* pLinkIconFileName /* <= Location of the icon file */
)
{
struct PlacemarkIcon
{
char m_extension[MAXEXTENSIONLENGTH];
int m_iconIndexX; /* X index of icon from left most edge */
int m_iconIndexY; /* Y index of icon from bottom most edge */
};
PlacemarkIcon extensionIcons[] =
{
{"url", 5, 7},
{"dgn", 0, 7},
{"jpg", 6, 7},
{"gif", 6, 7},
{"tif", 6, 7},
{"gif", 6, 7},
{"doc", 3, 7},
{"pdf", 2, 7},
{"mpg", 7, 7},
{"wav", 8, 7},
{"mp3", 8, 7},
{"xls", 4, 7},
{"dwg", 1, 7},
{"dxf", 1, 7},
}; int iconIndex = 0;
char extension[MAXEXTENSIONLENGTH];
extension[0] = '\0';
mdlFile_parseName (url, NULL, NULL, NULL, extension);
// Find an icon appropriate for the link's file extension. Default to
// "url" if extension is not found.
if (0 != strlen (extension))
{
for (int i=0; i < sizeof (extensionIcons)/sizeof (PlacemarkIcon); i++)
{
if (0 == strcmpi (extension, extensionIcons[i].m_extension))
{
iconIndex = i;
}
}
} // MicroStation's default custom placemark icons file.
// Distributed in Workspace\System\Image, so a relative path is OK.
sprintf (pLinkIconFileName, "GELinkIcons.png");
// Height and width of each icon in pixels
*pIconWidth = 32;
*pIconHeight = 32;
// Translate the index of the icon to be used into pixel coordinates.
*pIconX = extensionIcons[iconIndex].m_iconIndexX * *pIconWidth;
*pIconY = extensionIcons[iconIndex].m_iconIndexY * *pIconHeight;
// 1.0 is the default icon scale, but 0.7 is readable without being obnoxious.
*pIconScale = .7;
}
); // ExamplePlaceMarkProvider
Step Three: Tying it all together
Now that the placemark provider has been written, we can register it with the Google Earth exporter and translate our MicroStation document along with its link to KML. To do this, we need to declare a pointer to our provider, then pass that pointer to mdlKml_registerElementPlacemarkProvider() to inform the exporter that we have a callback method.
ExamplePlacemarkProvider* pPlacemarkProvider;
pPlacemarkProvider = new ExamplePlacemarkProvider;
mdlKml_registerElementPlacemarkProvider (pPlacemarkProvider);
After calling, mdlKml_exportToFile(), our placemark provider should be processed and a Google Earth file created. Once this has happened, the placemark provider should be unregistered using mdlKml_unregisterElementPlacemarkProvider().
mdlKml_unregisterElementPlacemarkProvider (pPlacemarkProvider);
delete pPlacemarkProvider;
The entire resulting function can be seen below:
void myGoogleEarthExport ()
{
IKmlCoordinateRemapperP pRemapper;
if (SUCCESS != mdlKml_getRemapper (&pRemapper, MASTERFILE))
return; KmlExportSettings settings;
mdlKml_getDefaultExportSettings (&settings); RscFileHandle rscHandle;
mdlResource_openFile (&rscHandle, NULL, FALSE); int viewToExport = mdlWindow_getSelectedViewIndex ();
char const* fileName = "C:\\Example.kmz";
MSWChar const* wName = L"Example";
MSWChar const* wDescr = L"An example KMZ file."; ExamplePlacemarkProvider* pPlacemarkProvider;
pPlacemarkProvider = new ExamplePlacemarkProvider;
mdlKml_registerElementPlacemarkProvider (pPlacemarkProvider); mdlKml_exportToFile (fileName, wName, wDescr, NULL, MASTERFILE, &settings, pRemapper,
viewToExport, rscHandle); mdlKml_unregisterElementPlacemarkProvider (pPlacemarkProvider);
delete pPlacemarkProvider; mdlKml_freeRemapper (&pRemapper);
mdlResource_closeFile (rscHandle);
}