Silverlight 3 introduces some new features. One that I was anxious to try out is the ‘Projection’ property. Charles Petzold took some time out from reading English novels to post some interesting experiments with this new feature.
Since I have been playing with the LidarServer WMS, I decided to apply some projection property enhancement to my LidarServer WMS viewer. The folks at USGS had partnered with some other government agencies to collect a set of LiDAR for the entire Denver metro area. This was needed for planning and security arrangements surrounding the Democratic National Convention last summer. This data was all made available to the public, presumably not terrorists. Mark Eaton, the NSDI liaison for Colorado, was kind enough to load this rather large data set onto a hard drive for me and I passed it over to the LidarServer folks to publish as a sample. This is a great resource and I hope other metro governments around the country can do the same. The really nice thing about the LiDAR for Denver, at least for my experiment, is that it includes lots of highrise buildings.
This is important only because LidarServer has incorporated a very useful extension to their WMS service. They added an additional non-spec request called GetProfileView. Basically this type of request gets the point cloud perpendicular to a profile line. The direction is determined by a kind of right hand rule pointing your thumb along a profile line with fingers curled in the direction of the cloud profile. Like many standards there are edges that are usefully broken. By adding the GetProfileView request to the WMS repertoire LidarServer opens a whole new dimension to viewing LidAr, the popularly known 3rd dimension.
Of course the desktop GIS folks have enjoyed this for some time, however, we in the browser interface world find this all fairly novel. The advent of Silverlight 3 starts things rolling down the road to 3D, but as Charles Petzold points out Silverlight 3 applies 3D transforms to 2D elements. Turning 2D elements into 3D objects is still problematic. I used Petzold’s first approach, utilizing the PlaneProjection class to set up my experiment.
First I had to have a way to draw profile lines and set GetProfileView properties, so I added a new expander panel. In the process I ran across a really helpful bit of code: http://silverlight.net/forums/p/12467/40404.aspx. There are more sophisticated DragDrop controls like DragDrop Manager, but the first code I ran across did the job well and was easy to understand. Adding any Silverlight control element inside of Canvas makes it draggable:
<Canvas x:Name="SpinProfileCanvas" Grid.Column="0" Grid.Row="0" Grid.RowSpan="2" HorizontalAlignment="Left" VerticalAlignment="Top"> <local:DragDropPanel x:Name="SpinProfileDragPanel"> . . </local:DragDropPanel> </Canvas>
I quickly made all my panels draggable using this code and changing all my menu panels from MapControl.MapLayer to plain ordinary Canvas layouts coextensive to the Map Control.
I started the draw profile code using the Polyline shape class. However, the transition from a Point collection to individual segments required by the GetProfileView request was cumbersome, especially since I wanted a rubber line hint while drawing. I finally switched to just a List collection of Line shapes. I could then iterate through the List and build all the requests for a series of profile line segments. These then appear in a ScrollViewer wrapped StackPanel inside a DragDropPanel as a horizontal series of Image elements.
Image img = new Image(); img.Source = new BitmapImage(new Uri(profileServer + lidarname + "? SERVICE=WMS&VERSION=1.3&REQUEST=GetProfileView &FORMAT=image/png&EXCEPTIONS=INIMAGE&CRS=EPSG:3785 &LEFT_XY=" + p0.X + "%2C" + p0.Y + "&RIGHT_XY=" + p1.X + "%2C" + p1.Y + "&DEPTH=" + DepthText.Text + "&SHOW_DRAPELINE=" + drapeline + "&SHOW_GRATICULE=" + graticule + "&WIDTH=800&HEIGHT=" + profileHeight + "&COLORIZATION=" + colorization + "&FILTER=" + filter)); bdr.Child = img; profileImages.Children.Add(bdr);
Because these are image sources it isn’t necessary to write a proxy service to get around the non-site of origin security restrictions. The result is a set of profiles, one for each line segment. I also added a rollover scroll affect so that as you roll over a line segment the associated profile scrolls into view.
Fig 2 – First Iteration of GetProfileView using a simple ScrollView
User Note: LidarServer imposes a 1000m limit on GetProfileView segment lengths. You’ll need to zoom to within a few blocks. Sorry, getting a profile of the Denver skyline isn’t possible. I already tried that. It does make sense to limit things to reasonable sizes.
This is interesting but not really Silverlight 3 Projection yet. The next enhancement added a rectangle draw tool to get four sides. These four sides could then be plugged into a set of Grids with Silverlight 3 Projection attributes:
<Grid x:Name="frontgrid" Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2" > <Grid.Projection> <PlaneProjection x:Name="front" LocalOffsetZ="100" RotationY="0" /> </Grid.Projection>
This Grid can then be populated with the profile image similar to the previous ScrollViewer , but the beauty here is that now the sides of my rectangle profiles can each be transformed into its own plane. Finally these planes can all be part of a Storyboard animation:
<Storyboard x:Name="RotationAnimation"> <DoubleAnimation Storyboard.TargetName="front" Storyboard.TargetProperty="RotationY" By="360" Duration="0:0:20" RepeatBehavior="Forever" />
Now I can draw a rectangle around a building such as Colorado’s Capitol, and see the four elevations of LiDAR point clouds rotating in a projection cube, actually ‘almost cube’. There is no top or bottom. I suppose I could grab a WMS GetMap for the top and even set a GetMap Filter to ‘Ground’ in order to fill in the bottom of a cube for a complete isometric view arrangement. That will be another project. I am also thinking about an n sided polygon profile tool, rather than the limited rectangle profile.
The Rectangle shape has some problems for stretching an area of interest. The Xaml Rectangle shape is defined by an upper left point along with width and height int attributes. However, the width and height throw out of range errors when negative which complicates life for an arbitrary stretchy rectangle draw. You’ll see from the example that it only draws from upper left to lower right. I decided to keep it this way for the time being, rather than using a 4sided polygon. One beneficial side affect is that the resulting rectangle shape has well defined north, south, east, west sides without resorting to a clockwise algorithm and a bit more code.
In the meantime I added some buttons for pause/resume on my animation as well as a grow/shrink on the elevation size. This lets me see some of the taller buildings where the lower profiles just don’t cut it. It may be worth adding a stretch capability to the Image Panel to let these adjustments be arbitrary sizes. You notice that the Projection attributes can also nest other elements like buttons and text. Buttons still have their full event driven nature. You gotta love recursion! So I popped a full screen button onto my rotating profile image. You have to be quick to click a moving button, but the reward is a new “draggable” panel with a 2500px max dimension profile request. Lots of detail. Besides you can always pause the rotation nonsense first.
Not bad for a few days work! I liked this little exercise because it illustrates the power of a declarative XML graphics grammar like xaml. We are not talking tons of development effort to get a rather sophisticated browser interface. Silverlight is raising the bar on user expectations and it will be interesting to see how this works out in the more traditional world of GIS.
Silverlight 3 raises the bar on expectations, but also portends change by dragging more stuff into the client. Traditional GIS was very much a desktop deal, however, you can see changes coming, and perhaps more rapidly than we suppose. We may be nearing a technology tipping point here.
This all reminds me of an earlier transition in GIS, when the data layer broke away from monolithic GIS systems, becoming an independent ‘plug & play’ component with various DB vendors taking chunks of GIS functionality for themselves. In this case we’re seeing the browser client starting to take chunks out of the traditional GIS middle tier. With Silverlight, vectors have moved out to the client. The necessary number of round trips found in older web technologies made these types of interfaces prohibitive. (Anybody still remember ArcIMS?) Silverlight shrinks the desktop performance advantage and moves some more chunks of GIS out of the server. I don’t know if this is good or bad, but it sure is fun!