Feeds:
Posts
Comments

Posts Tagged ‘GIS’

On the way of introducing a compass to my GIS prototype, I came across an implementation idea that I would like to share.

Well structured and designed applications often separate user interface and domain business layers. Data binding is one of the great means introduced in WPF that aims and helps developers efficiently decouple their user interfaces from the rest of the application.

The following XAML code creates a window containing a slider and an image control. The idea is to rotate the image by a rotation angle given by the slider control.
<Window x:Class="Exercises.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="278" Width="356">
<StackPanel Name="stackPanel">
<Label Content="{Binding ElementName=slider, Path=Value}" Height="28" Name="label1" />
<Slider Name="slider" Height="23" Margin="12,58,0,0" Width="307" Maximum="360" ValueChanged="slider_ValueChanged" />
</StackPanel>
</Window>

If you are coming from WinForms world, you would capture the ValueChangedEvent of the slider and do the following:

private void slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) {
   double rotationAngle = slider.Value;
   stackPanel.Children.Remove(compassDrawing);
   compassDrawing = DrawImage(rotationAngle);
   stackPanel.Children.Add(compassDrawing);
}
UIElement DrawImage(double rotationAngle) {
   // Create a 100 by 100 image with an upper-left point of (75,75).
   ImageDrawing compassImage = new ImageDrawing();
   compassImage.Rect = new Rect(0, 0, 200, 200);
   compassImage.ImageSource = new BitmapImage(
    new Uri(@"D:\Documents\Visual Studio 2010\Projects\Exercises\Exercises\Images\compassImage.png", UriKind.Relative));
    // Use a DrawingImage and an Image control to display the drawing.
    DrawingImage drawingImageSource = new DrawingImage(compassImage);
    // Freeze the DrawingImage for performance benefits.
    drawingImageSource.Freeze();

    Image imageControl = new Image();
    imageControl.Stretch = Stretch.None;
    imageControl.Source = drawingImageSource;
    imageControl.RenderTransform = new RotateTransform(rotationAngle, compassImage.Rect.Width/2, compassImage.Rect.Height/2);
    // Create a border to contain the Image control.
    Border imageBorder = new Border();
    imageBorder.Child = imageControl;
    return imageBorder;
}

The slider_ValueChanged event handler will replace the previous image in the main stack panel by a newly generated image. The DrawImage() method will draw a new rotated image given an angle as a parameter.

Figure 1 : Non rotated image

Figure 1 shows a non rotated image that is shown either at application start up or when the slider’s value is set to 0 or 360 degrees.

Figure 2 in the other hand shows the result when the slider is set to a given value:

Figure2: Rotated image

If we look back to the code now, there is clearly a smell of a binding possibility out there!

The compass image can have a property, say Rotation which, whenever changed, the image rotates automatically without involving event handlers.

Looking to the UI controls used above, none of them supports this functionality. A great opportunity for us to do some custom data binding.

Read Full Post »

The most important part of my drawing engine is almost done. In this post, I will talk about a coding mistake that took me almost a day to resolve hoping this will save some precious time to others. I spent a couple of hours adding a new renderer to my GIS application capable of drawing custom data layers. Done with implementing all drawing steps and got to display the final result and… Nothing on the screen!

Here is a code sample, part of the new rendering class

public DrawingVisual Render(Geometry geo){
      DrawingVisual drawingVisual = new DrawingVisual();
      DrawingContext drawingContext = drawingVisual.RenderOpen();
      // Draw geometry
      drawingContext.DrawGeometry(Brushes.Red, new Pen(Brushes.Blue, 2), geom);
      return drawingVisual;
}

This bit of code does obviously not work! Every thing seems to be right in place but something hidden somewhere is wrong making the shapes not to appear on the screen.
In fact, there was one line missing! The drawing context was left open and that is the reason why my drawings were not reflected on the screen.
I fixed the issue by adding the following line at the end of the “Render” method.

      drawingContext.Close();

Read Full Post »

WPF is making a lot of noise these days, I was wondering what this new technology is all about and decided to give it a try.

Coming from WinForm world, describing GUIs in text (XAML) seemed awkward to me, I struggled a bit  getting my first window up and running but managed to do so at the end.

In order to understand what is laying underneath WPF, I thought I should write my proper user control that can display something like a map.

Here is a screenshot of my first attempt to write such a control.

This control is based on SharpMap (http://sharpmap.codeplex.com/), reads and displays ESRI shape files.

For now, I am using SharpMap as it is. All what I did is to use the library, load some shape files and display them in an image control.

// Event handler for button click
public void OpenShapeFileClicked(object sender, EventArgs e){
      // ... ask the user to provide a shape file using a file open dialog control
      LoadShapeFile(path_provided_by_user);
}
public void LoadShapeFile(string fileName){
      SharpMap.Layers.VectorLayer myLayer = new SharpMap.Layers.VectorLayer("ShapeFiles");
      myLayer.DataSource = new SharpMap.Data.Providers.ShapeFile("path_to_file", true);
      myLayer.Style.Fill = System.Drawing.Brushes.GreenYellow;
      myLayer.Style.Outline = new System.Drawing.Pen(System.Drawing.Brushes.Gray);
      myLayer.Style.Line.Width = 2;
      myLayer.Style.Line = new System.Drawing.Pen(System.Drawing.Brushes.Black);
      myMap.Layers.Add(myLayer);
      myMap.ZoomToExtents();
      DrawImage();
}
private void DrawImage(){
      // Convert System.Drawing.Image to ImageSource to wich an image is bound
      using (Bitmap bitmap = new Bitmap(myMap.GetMap())){
             IntPtr hBitmap = bitmap.GetHbitmap();
             // Use System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap
             BitmapSource bitmapSource = CreateBitmapSourceFromHBitmap(
                hBitmap,
                IntPtr.Zero,
                Int32Rect.Empty,
                BitmapSizeOptions.FromEmptyOptions());
             // Set image1 control data source
             image1.Source = bitmapSource;
      }
}

This project is not about rewriting a new SharpMap library for WPF but rather build up a WPF application from scratch based on SharpMap which I strongly believe will give me a great insight of the WPF technology and how GIS applications work.

In this little introduction, we demonstrated how easy it is to create a basic GIS application using WPF.

To be continued…

Read Full Post »