Wednesday 29 May 2013

Announcing: MapGuide Maestro 5.0 RC1 and 4.0.5 maintenance

Wow! It's actually been 6 months since I announced the previous 5.0 beta and 4.0.x stable release! Ok, it's time to get this thing out the door.

Here's the first Release Candidate and a matching 4.0.5 maintenance release with bugfixes.

Here's what's new in the Release Candidate. This is the last of the new features for 5.0. It will be all bug fixes from here to the final release.

Live Map Definition Editor Improvements

The Live Map Definition Editor we introduced in beta 2 has undergone some major improvements.

We can now view Feature Sources in the Repository View. Resources in the Repository View can also be edited in-place.



This launches an XML editor allowing you to edit and preview the resource content.



Why do we launch an XML editor and not a specialized one? Because the code that allows us to resolve a specialized editor based on a given resource and schema version is currently tightly bound to the Maestro AddIn infrastructure. The Live Map Definition editor is a standalone tool and does not use this infrastructure so we can't tap into this same code. We'll eventually be able to launch a specialized editor, but that will involve a big refactoring job that we'll only realistically do once 5.0 is out the door.

We've also implemented most of the drag/drop processes that are possible to maximize productivity. All the drag/drop actions that are now possible with this release are outlined in the images below.




Fusion Editor Enhancements

The Fusion Editor has undergone several enhancements. The Widget Management dialog is now a tabbed interface, to accommodate a new XML editor to edit the special Map Widget. Previously, there was no means through the Fusion editor to edit the map widget.


Existing widget management functionality has been moved to the "Other Widgets" tab.


As I've talked about previously, this release includes the editor changes to distinguish between dockable and non-dockable widgets.

In order to provide a consistent interface and to reduce developer/maintenance effort, we've removed all specialized widget editors for this release. The reason is simply that there is just too much effort involved to give each widget in Fusion its own specialized editor (there's a lot of widgets!). Not to mention that widgets may be improved upon individually and not necessarily tied to a new MapGuide release, making the task of having our specialized UIs in sync and up to date quite difficult.

You're probably used to editing widgets via its XML anyway, so for the purposes of simplicity that's the only option we'll be giving you. But to make things just a bit easier, the Generic widget editor now uses the ICSharpCode text editor to provide XML highlighting.


More Feature Source Shortcuts

We've added some extra context menu commands to provide common shortcut operations for Feature Sources.

Firstly, a new shortcut to test a Feature Source connection bypassing the need to open the Feature Source in an editor.


Secondly, a new shortcut to automatically create a default layer for each feature class in the Feature Source


This will walk the schema of the feature source and present a list of Feature Classes for you to make layers from.


Choose the folder to create the layers in and this will then create a default layer in the chosen folder for each selected Feature Class. This is a nice convenient shortcut to rapidly create layers from a Feature Source. The supported geometry types of each Feature Class is used to determine what default styles to create. For example, if the geometry of a Feature Class only supports points, then only a Point style will be created for the default layer.

Runtime Map Inspector

The Runtime Map Inspector tool now includes a "Draw Order" tab so you can see how the layers are ordered display-wise.



Re-pointer

The resource re-pointer context menu command now supports re-pointering any resource that has dependencies (ie. Any resource type in this diagram that has a downward-pointing arrow to another resource type)

For those wondering what this command even does. The re-pointer command allows you to have all references of a selected resource to "re-point" to another resource of your choosing. An example usage scenario would be if you had a bunch of layers pointing to a dev/test Feature Source and you want to switch said layers over to your production Feature Source. This command provides a nice convenient way to easily make such a switch.

GDAL Feature Sources

The GDAL Feature Source editor now supports the new resampling method parameter introduced in the 3.8.0 iteration of the FDO provider (included with MapGuide Open Source 2.5)


This feature has also been backported to 4.0.5

Large File upload support over HTTP

This isn't so much a new feature, but rather a fix that allows you to upload really large files over the mapagent HTTP interface without the risk of OutOfMemoryExceptions happening. The previous implementation naively used a MemoryStream to store the entire uploaded file before sending to the mapagent, which if you're trying to load say a SDF file that's several GBs in size, will easily trigger the OutOfMemoryException.

This new implementation will instead stream the contents from a file location (we'll dump the input stream to a temp file if required) to the mapagent. This method is much more memory efficient and can easily handle files several GBs in size. This is the same technique we currently use for the Local and LocalNative implementations. Now all 3 implementations of SetResourceData use this method.

With this support, Maestro can now load package files several GBs in size in a non-transactional fashion regardless of underlying implementation (HTTP, Local or LocalNative) in a memory-efficient manner without breaking a sweat. We say non-transactional because doing this transactionally will still probably trigger the OOM, except on the MapGuide Server end as it will probably be trying to read the entire package file into memory in order to be able to load it.

Realistically speaking, we're not saying or recommending that you use this new capability to actually upload files several GBs over the internet. Rather, this capability is for intranet/localhost HTTP connections to your MapGuide Server where you want to be able to easily upload really large files without concern for bandwidth and memory usage.

This support has also been backported to 4.0.5

So I've said all that needs to be said. Go forth and download

Thursday 23 May 2013

An elegant MgMap hack

Ever wanted to set any of the following properties of a MgMap in your application code, but bemoan the fact that all these properties are read-only in the MgMap class?

  • DPI
  • Display Width
  • Display Height
  • View Center
  • View Scale
Here's a neat little hack you can do

If you remember, I previously showed how you can actually replicate mapagent functionality through the MgHttpRequest and MgHttpResponse classes. Armed with this knowledge, the key to changing any of the above properties is to set up the appropriate operation and parameters for an API that's only available in the mapagent: GETDYNAMICMAPOVERLAYIMAGE

GETDYNAMICMAPOVERLAYIMAGE differs from what's in the official API (MgRenderingService::RenderDynamicOverlay()) in that the mapagent version supports these additional parameters:
  • SETVIEWCENTERX
  • SETVIEWCENTERY
  • SETVIEWSCALE
  • SETDISPLAYDPI
  • SETDISPLAYWIDTH
  • SETDISPLAYHEIGHT
  • SHOWLAYERS
  • HIDELAYERS
  • SHOWGROUPS
  • HIDEGROUPS
These parameters actually modify the state of the MgMap that is to be rendered. Through the use of MgHttpRequest and MgHttpResponse we can indirectly tap into this mapagent API to achieve the same result.

Now the operation itself returns a rendered image obviously, so if we want this to be snappy (as we just want to modify MgMap state and don't really care about the rendered result), you'd want to request something that requires very minimal processing overhead to produce the rendered image. So under these conditions, the ideal parameters to supply to GETDYNAMICMAPOVERLAYIMAGE are:
  • BEHAVIOR = 1 (Selected features only)
  • FORMAT=PNG8/JPG (Smallest image format in case we actually do have a rendered selection)
I've attached a PHP code sample that demonstrates this technique.

Saturday 18 May 2013

MapGuide tidibts: The resource dependency chain

You probably know in MapGuide that there is a whole different bunch of type of resources available at your disposal, when authoring up your data, maps and applications.

You probably also know that if you move, rename or delete a resource you may be affecting and/or breaking other resources that depend on it.

How about the big picture? Well here's one I've prepared earlier.

As you can see, with the exception of the Load Procedure, Application Definition and Web Layout, every other resource type has a dependency on another resource type.

Consider what you may be potentially breaking when you move, rename or delete a given resource.

Wednesday 15 May 2013

The lab experiment is evolving

And no, I am not trying to build a new MapGuide viewer. :)

This new feature just makes such as task dead simple


Saturday 11 May 2013

MapGuide tidbits: Maximizing .net code reuse

Code reuse is always a good thing. If you use the .net MapGuide API, you may want to consider some options that can enhance re-usability of your code.

For those who don't know, the MapGuide API is an extension of a common subset known as the Geospatial Platform API. AutoCAD Map3D extends this subset to integrate with AutoCAD Map3D, MapGuide extends this common subset to support web applications and mg-desktop extends this subset to give you a portable MapGuide environment for your desktop applications.



As you can see from the diagram there are key abstract classes in the Geospatial Platform API that are derived by the various implementations (bolded for emphasis). It just so happens that these classes are the key classes for working with maps and layers and the rest of the API through service classes.

By writing your .net code to work against the abstract classes in the Geospatial Platform API, you get to maximize its reuse against the various extensions of this common subset. For example, have your code:
  • Work against MgMapBase instead of MgMap, MgdMap or AcMapMap
  • Work against MgLayerBase instead of MgLayer, MgdLayer or AcMapLayer
  • Work against MgResourceService instead of AcMapResourceService or MgdResourceService
You hopefully get the idea. Where possible, work against the abstract class instead of the concrete implementation.

Writing code this way makes the code more amenable to easy manual dependency injection, with your MapGuide, mg-desktop or AutoCAD Map3D specific code doing the actual injecting, but the dependency injectee not having to care because it works against the abstract class and not the concrete implementations, thus allowing this injectee code to be re-used anywhere that can provide a concrete implementation of the class.

Of course, each extension of the common subset has their own implementation quirks. AutoCAD Map3D has some, mg-desktop has some too. But if such quirks do not affect you, then this coding strategy is something to consider if you want to re-use such code beyond MapGuide web applications.

Another lab experiment


Saturday 4 May 2013

One request to rule them all

Seriously, image Data URIs are the absolute bomb!





Thursday 2 May 2013

MapGuide tidbits: MgByteReader and friends

This one's a bit of a post for newbies, so you can skip it if you already know this stuff :)

If you look at the various bits of the MapGuide API, you'll probably see lots of references to MgByteReader lying around. An API will either return one or require one as part of its method parameters.

What is a MgByteReader? A MgByteReader is basically a MapGuide analogue to your Stream class in .net/Java and serves the same purpose: an unified I/O abstraction for things that can be fed into the MapGuide API and things that are returned from the MapGuide API. Things like.

  • Images (of rendered maps/selections)
  • Resource Data files (to download/upload)
  • XML files (to/from the repository)
  • DWF files (for DWF ePlots)
So if you're given an MgByteReader from a particular API, what can I do with it? Similarly, if an API requires passing in a MgByteReader, how can I make one?

Here's a diagram I made up that should explain everything to you.




Since MgByteReader is basically a stream, you might be wondering if the .net/Java/PHP wrappers to the MapGuide API provides any adapters to allow MgByteReader objects to be consumed as Stream objects, so you don't have to do any manual conversion. For PHP and Java, you're out of luck. You'll have to dump the MgByteReader into a supported form as per the above diagram, and then work from there.

For .net however, I've already solved this problem for you :) If you're using the Maestro API (that wraps both the official MapGuide API and the mapagent interface), for APIs that return MgByteReader objects Maestro provides wrapper APIs that return System.IO.Stream objects instead. Similarly for APIs that take MgByteReader parameters, Maestro's wrapper API takes System.IO.Stream objects.

If you're not using Maestro, there's a MgReadOnlyStream class I wrote for mg-desktop that can easily be reused for your own .net applications if you require a System.IO.Stream adapter. MgReadOnlyStream provides mg-desktop an easy way to convert the output of a rendering service API into something that requires a System.IO.Stream (eg. a System.Drawing.Image). That's pretty much the gist of how our mg-desktop viewer works, taking MgByteReader objects from the rendering service, wrapping it into a MgReadOnlyStream and feeding that to a System.Drawing.Image, to then be painted onto a WinForms control surface.

Hope this helps.