Vishful thinking…

Raster statistics + SIMD === winning

Posted in .NET, C#, GIS by viswaug on February 8, 2016

Recently, the .NET framework 4.6 enabled features that would allow us to leverage SIMD (Single Instruction Multiple Data) capabilities that have been present in our CPUs since the 2000s and deliver faster performance for calculating raster statistics.

We were using the .NET bindings for GDAL to calculate a few simple raster statistics for reporting needs. I got curious as to the kind of performance boost that we could be seeing if we leveraged SIMD for this purpose. So, I created a little console app to explore the performance gains. Here is what i observed.

To start off, we need to check if our CPU supports SIMD instructions. Although, I expect that everyone’s computer will support SIMD, here is simple way to check. Download and run CPU-Z. Keep an eye out for the SSE instructions as shown below.

cpuz

Clone the git repo or just download the executable from here. And run the SIMD.exe file with a GeoTIFF file as a parameter. Needless to say, the console app is pretty rudimentary and was written solely to observe SIMD performance gains. I would highly encourage you to clone the repo and explore further if you are interested. The app currently just reads all the raster image into memory and sums all the values to produce a total sum. Not very useful, but i am hoping it can get you started in the right direction to explore further. The amount of code required or in other words to modify your current app to leverage should be manageable and shouldn’t require a complete rewrite. Also, currently the SIMD support in the .NET framework only works under 64-bit and in release mode. That had me stumped for a bit. But, there is very useful “IsHardwareAccelerated” Flag that helps you find out if your vectorized code is actually reaping the benefits of the SIMD hardware.

Raster X size: 28555
Raster Y size: 17939
Raster cell size: 512248145
Total is: 146097271
Time taken: 4568
SIMD accelerated: True
Another Total is: 146097271
Time taken: 1431

Here is the result from a run on a sample raster image. With the SIMD vectors, the execution went from 4568 to 1431 milliseconds. That’s almost 1/3 of the original time. Pretty tempting isn’t it?

The performance measure doesn’t really prove anything and is purely meant to satisfy my own curiosity. Your mileage may vary. To eek out any gains out of using SIMD vectors, you will need to be processing a large enough array that will justify the overhead of creating the SIMD vectors.

I realize that pretty much everything needs to be available in JavaScript to be relevant these days 🙂 So, if JavaScript is your cup of tea FireFox has experimental support for SIMD vectors. Soon we will be running raster statistics on the browser. Actually, we currently are running some raster statistics but without the SIMD bits. Hopefully, i will get around to writing about that soon.

Clone the repo here

Advertisements

MBTilesViewer

Posted in .NET, ArcGIS, C#, ESRI, GIS, Utilities by viswaug on June 28, 2011

I also created this bare bones MBTiles cache viewer to view the tile cache in MBTiles format. This application does not do much, just display the tilecache on a map. To view a MBTiles file, just fire up the viewer and start dragging and dropping MBTiles cache files on to it. You can drag and drop multiple MBTiles cache files at the same time if needed. And also, you can create MBTile caches with the TileCutter. The viewer was created using the ESRI WPF map control. If you would like to see this viewer do more, let me know 🙂

MBTilesViewer can be downloaded here.

TileCutter update – With support for OSM and WMS map services

Posted in .NET, ArcGIS, C#, ESRI, GIS, OpenSource, Utilities by viswaug on June 28, 2011

I just added support for creating MBTiles caches for WMS map services and also to download OSM tiles into the MBTiles format. MBTiles cache for WMS map services would improve map rendering performance, but why did i add support for OSM tile sets? Well, they will come in handy for disconnected/offline use cases. So, here are some usage examples

ArcGIS Dynamic Map Service:

TileCutter.exe -z=7 -Z=9 -x=-95.844727 -y=35.978006 -X=-88.989258 -Y=40.563895 -o=”C:\LocalCache\ags.s3db” -t=agsd -m=”http://server.arcgisonline.com/ArcGIS/rest/services/I3_Imagery_Prime_World_2D/MapServer”

WMS Map Service 1.1.1:

TileCutter.exe -z=7 -Z=9 -x=-95.844727 -y=35.978006 -X=-88.989258 -Y=40.563895 -o=”C:\LocalCache\wms111.s3db” -t=wms1.1.1 -m=”http://sampleserver1-350487546.us-east-1.elb.amazonaws.com/ArcGIS/services/Specialty/ESRI_StateCityHighway_USA/MapServer/WMSServer”

WMS Map Service 1.3.0:

TileCutter.exe -z=7 -Z=9 -x=-95.844727 -y=35.978006 -X=-88.989258 -Y=40.563895 -o=”C:\LocalCache\wms130.s3db” -t=wms1.3.0 -m=”http://sampleserver1-350487546.us-east-1.elb.amazonaws.com/ArcGIS/services/Specialty/ESRI_StateCityHighway_USA/MapServer/WMSServer”

OSM:

TileCutter.exe -z=7 -Z=9 -x=-95.844727 -y=35.978006 -X=-88.989258 -Y=40.563895 -o=”C:\LocalCache\osm.s3db” -t=osm -m=”http://tile.openstreetmap.org”

And always just type “TileCutter -h” for usage information.

Want to customize the parameters with which the maps are being generated? Just use the “-s” command line option ans specify the setting in a query string format.

TileCutter.exe -z=7 -Z=9 -x=-95.844727 -y=35.978006 -X=-88.989258 -Y=40.563895 -o=”C:\LocalCache\ags.s3db” -t=agsd -m=”http://server.arcgisonline.com/ArcGIS/rest/services/I3_Imagery_Prime_World_2D/MapServer” -s=”transparent=true&format=jpeg”

Also, if some of the tile requests result in errors, the level, column, row and error message information would be logged into a text file in the same directory as the MBTiles cache.

And now, for the best new feature of TileCutter, the program does not store duplicate tiles. That is, if the area you are caching has a lot of empty tiles in the ocean etc, the MBTiles cache created by TileCutter will only store one tile for all those duplicated tile images. Should help save disk space 🙂

TileCutter can be downloaded here

TileCutter – A small utility to generate tile cache in the MBTiles format from ArcGIS Dynamic Map Services

Posted in C#, ESRI, GIS, Uncategorized by viswaug on June 12, 2011

Thought I would share a little utility I had written up to generate tile caches in the MBTiles format for ArcGIS Dynamic Map Services. The MBTiles cache format is very simple and makes moving caches between machines very easy since you just have to transfer one file instead of the thousands of files that need to be copied for normal tile caches. The TileCutter is a console utility and accepts the scale range and the extent in latitude/longitude for which the cache should be generated. It also takes a few other options listed below.

Options:
  -h, --help                 Show this message and exits
  -m, --mapservice=VALUE     Url of the ArcGIS Dynamic Map Service to be
                               cached
  -o, --output=VALUE         Location on disk where the tile cache will be
                               stored
  -z, --minz=VALUE           Minimum zoom scale at which to begin caching
  -Z, --maxz=VALUE           Maximum zoom scale at which to end caching
  -x, --minx=VALUE           Minimum X coordinate value of the extent to cache
  -y, --miny=VALUE           Minimum Y coordinate value of the extent to cache
  -X, --maxx=VALUE           Maximum X coordinate value of the extent to cache
  -Y, --maxy=VALUE           Maximum Y coordinate value of the extent to cache
  -p, --parallelops=VALUE    Limits the number of concurrent operations run
                               by TileCutter
  -r, --replace=VALUE        Delete existing tile cache MBTiles database if
                               already present and create a new one.

Example Usage:

To just try it out, just run TileCutter.exe, it will download tiles for some default extents from an ESRI sample server

TileCutter -z=7 -Z=10 -x=-95.844727 -y=35.978006 -X=-88.989258 -Y=40.563895 -o=”C:\LocalCache” -m=”http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Population_World/MapServer”

The TileCutter does request tiles in parallel threads and allows to you controls the number of concurrent operations. I don’t want to write too much about it yet since i am still working to add more capabilities to it. I am planning on providing the ability to generate MBTile caches for WMS services, OSM tiles etc in the future and more if there is interest. Also, planning on implementing  a way to avoid storing duplicate tiles(for example, empty tiles in the ocean etc). I just wanted to get the tool out there early to get feedback and guage interest. So, if you have queries/interest/feature requests, let me know 🙂

Also, I will blog about a little piece of code for a IHttpHandler that will serve up the MBTiles to web clients pretty soon. Stay tuned…

TileCutter can be download here.

Enhance your development experience with the ESRI Silverlight API using the Microsoft Reactive Extensions

Posted in .NET, ArcGIS, C#, ESRI, Uncategorized by viswaug on January 31, 2010

In my humble opinion, Reactive Extensions is one of the most exciting libraries to come out of Microsoft lately. And that is saying a lot since there have been quite a bit of good libraries coming out of Redmond recently. The Rx for .NET takes a lot of pain out of asynchronous programming and has drastically reduced the amount of code required to handle and orchestrate responses from multiple web services. Given that Silverlight is a client-side technology, most of the Silverlight applications make calls to web services and display results to the user as needed. A common application scenario is where the Silverlight client needs to make multiple calls to multiple web services and orchestrate calls to other web services based on responses from previous web service calls. Handling this scenario can get quite a bit complicated when you have to maintain contexts to store response states from the various web services. This is where Rx for .NET comes in real handy. The following scenario and the solutions should illustrate how Rx for .NET can help when programming with the ESRI Silverlight API for example.

When adding ArcGIS Map service layers to the Map control in the ESRI Silverlight API, the map control makes a HTTP request for every layer added to request the metadata for the map service. Depending on whether the request to the service metadata succeeds or fails the layer object would raise a ‘Initialized’ event or a ‘InitializationFailed’. So, a layer ‘load’ can be considered to be complete when either the ‘Initialized’ or the ‘InitializationFailed’ has fired. If we want to initiate another sequence of operations when all the ‘load’ of all the layers on the map have completed, like say populate a legend/ Table of Contents, then we will have to wait for all the layer ‘load’ to be complete (Success/Failure). Making a request to the legend web service in the above scenario can get quite cumbersome. But Rx for .NET can simplify things quite a bit. Follow the code sample below to accomplish the task.

The two extension methods below will help us watch for the ‘load’ complete for a layer and to watch for all the layers in a LayerCollection to complete. As you can see, we use the ‘Merge’, ‘Take’ and the ‘ForkJoin’ observable extension methods on the IObservable to watch for the right sequence of events.

public static class ExtensionMethods

{

    public static IObservable<IEvent<EventArgs>> GetLayerLoadCompleted( this Layer layer )

    {

        if( layer == null )

            throw new ArgumentNullException( "layer" );

 

        if( layer.IsInitialized == true )

        {

            IEvent<EventArgs>[] events = new IEvent<EventArgs>[ 1 ] { null };

            events.ToObservable<IEvent<EventArgs>>();

        }

 

        IObservable<IEvent<EventArgs>> oSuccess = Observable.FromEvent<EventArgs>

            (

                ev => layer.Initialized += ev,

                ev => layer.Initialized += ev

            );

 

        IObservable<IEvent<EventArgs>> oFailed = Observable.FromEvent<EventArgs>

            (

                ev => layer.InitializationFailed += ev,

                ev => layer.InitializationFailed += ev

            );

 

        IObservable<IEvent<EventArgs>> obsCompleted = oSuccess.Merge<IEvent<EventArgs>>( oFailed );

 

        IObservable<IEvent<EventArgs>> oFirst = obsCompleted.Take<IEvent<EventArgs>>(1);

 

        return oFirst;

    }

 

    public static IObservable<IEvent<EventArgs>[]> GetLayersLoadCompleted( this IEnumerable<Layer> layers )

    {

        if( layers == null )

            throw new ArgumentNullException( "layers" );

 

        return Observable.ForkJoin<IEvent<EventArgs>>

            (

                from item in layers

                select item.GetLayerLoadCompleted()

            );

    }

}

And now, we can add a handler to be executed when all the layers have loaded like below.

public MainPage()

{

    InitializeComponent();

 

    IDisposable subscription = null;

    subscription = myMap.Layers.GetLayersLoadCompleted().Subscribe

        (

            ( args ) =>

            {

                HtmlPage.Window.Alert( "All layers have loaded." );

                subscription.Dispose();

            }

        );

}

Making HTTP Post with Silverlight a little easier

Posted in C#, Silverlight by viswaug on September 29, 2009

In my earlier post, I talked about how to go about making an HTTP Post in Silverlight. The whole process is a little complicated to say the least. Silverlight does not come with an utility class like WebClient that makes making a HTTP Get a little easier. So, I created a class called ‘HTTPPostHelper’ that does for HTTP Post what WebClient does for HTTP Get. The ‘HTTPPostHelper’ class listed below, makes the whole process a lot easier. To use the class, do the following

  • Create an instance of the HTTPPostHelper class with the type of the input class (T) and the type of the returned class (K) as the generic arguments.
  • Listen to the ‘PostCompleted’ event that gets called when the Post operation completes successfully. The EventArgs of the event contains an instance of the return class type.
  • Listen to the ‘PostFailed’ event that gets called when the Post operation fails. The EventArgs of the event contains the exception information.
  • Call the ‘Post’ method on the HTTPPostHelper with the input object and the URL address to make the Post operation happen.
  • The input object gets serialized by default using the DataContractSerializer. But this can be overridden by setting the Serializer property of the HTTPPostHelper with an appropriate delagate that serializes the input object to a stream.
  • The output from the HTTP Post operation is deserialized by default using the DataContractSerializer. But this too can be overridden by the Deserializer property of the HTTPPostHelper.
  • For example, if you want to send and receive JSON data to the HTTP endpoint, just override the default Serializer & Deserializer with delegates that use DataContractJsonSerializer instead or your own custom binary serializer if need be.
  • The ‘ContentType’ used for the Post operation can also set before calling the Post method.
  • The class handles all the thread hopping internally. The ‘PostCompleted’ and the ‘PostFailed’ events get raised on the same thread from which they were called from.

 

public class HTTPPostHelper<T, K>

{

    SynchronizationContext syncContext;

    HttpWebRequest _request;

 

    public string ContentType

    {

        get;

        set;

    }

 

    public event EventHandler<EventArgs<K>> PostCompleted;

 

    public event EventHandler<ExceptionEventArgs> PostFailed;

 

    public Action<T, Stream> Serializer = null;

 

    public Func<Stream, K> Deserializer = null;

 

    public HTTPPostHelper()

    {

        Serializer = DefaultSerializer;

        Deserializer = DefaultDeserializer;

        ContentType = “application/stream”;

    }

 

    void DefaultSerializer(T input, Stream output)

    {

        DataContractSerializer serializer = new DataContractSerializer(typeof(T));

        serializer.WriteObject(output, input);

        output.Flush();

    }

 

    K DefaultDeserializer(Stream input)

    {

        DataContractSerializer serializer = new DataContractSerializer(typeof(K));

        K result = (K)serializer.ReadObject(input);

        return result;

    }

 

    public void Post(Uri address, T input)

    {

        syncContext = SynchronizationContext.Current;

 

        _request = (HttpWebRequest)WebRequest.Create(address);

        _request.Method = “POST”;

        _request.ContentType = “application/stream”;

 

        _request.BeginGetRequestStream(new AsyncCallback(PostRequestReady), new HttpWebRequestData<T>()

        {

            Request = _request,

            Data = input

        });

    }

 

    private void PostRequestReady(IAsyncResult asyncResult)

    {

        HttpWebRequestData<T> requestData = asyncResult.AsyncState as HttpWebRequestData<T>;

        HttpWebRequest request = requestData.Request;

        Stream requestStream = request.EndGetRequestStream(asyncResult);

        Serializer(requestData.Data, requestStream);

        requestStream.Close();

 

        request.BeginGetResponse(new AsyncCallback(PostResponseCallback), request);

    }

 

    private void PostResponseCallback(IAsyncResult ar)

    {

        try

        {

            HttpWebRequest request = ar.AsyncState as HttpWebRequest;

            HttpWebResponse response = request.EndGetResponse(ar) as HttpWebResponse;

            Stream responseStream = response.GetResponseStream();

            K urls = DefaultDeserializer(responseStream);

 

            syncContext.Post(PostExtractResponse, new HttpWebResponseData<K>()

            {

                Response = response,

                Data = urls

            });

        }

        catch (Exception ex)

        {

            syncContext.Post(RaiseException, ex);

        }

    }

 

    private void RaiseException(object state)

    {

        Exception ex = state as Exception;

        if (PostFailed != null)

            PostFailed(this, new ExceptionEventArgs(ex));

    }

 

    private void PostExtractResponse(object state)

    {

        HttpWebResponseData<K> responseData = state as HttpWebResponseData<K>;

        if (PostCompleted != null)

            PostCompleted(this, new EventArgs<K>(responseData.Data));

    }

}

 

public class ExceptionEventArgs : EventArgs

{

    public Exception ExceptionInfo { get; set; }

 

    public ExceptionEventArgs(Exception ex)

    {

        ExceptionInfo = ex;

    }

}

 

 

 

public class EventArgs<T> : EventArgs

{

    private T eventData;

 

    public EventArgs(T eventData)

    {

        this.eventData = eventData;

    }

 

    public T EventData

    {

        get

        {

            return eventData;

        }

    }

}

Making a HTTP Post in Silverlight a.k.a thread hopping

Posted in C#, Silverlight by viswaug on September 17, 2009

Making a HTTP GET request is as easy as pie using the WebClient class that is available in the Silverlight library. The DownloadStringCompleted event callback of the WebClient class is invoked on the main UI thread thus allowing the developer to access UI elements in the callback method itself. If the web service call resulted in a failure, then that condition can be easily determined in the DownloadStringCompleted event callback method by checking if the Error property on the DownloadStringCompletedEventArgs argument passed into the callback method is NULL. The code snippet below illustrates one way to use the WebClient class.

    WebClient webClient = new WebClient();

    webClient.DownloadStringCompleted += (sender, e) =>

    {   

        if (e.Error == null)   

        {       

            //Process web service result here       

            txtBox.Text = e.Result;   

        }    else   

        {       

            //Process web service failure here       

            txtBox.Text = e.Error.Message;   

        }    callback();

    };

    webClient.DownloadStringAsync( new Uri( “URL address that needs to be fetched” ) );

 

But when it comes to making a HTTP POST in Silverlight, things aren’t so simple. Silverlight doesn’t come with any helper classes like the WebClient (for making HTTP GET requests) to help take the hassle out of making a HTTP POST. So, to make a HTTP POST request, we must jump through two threads before we get back on the main UI thread where we will be able to access the UI elements and update them as needed. Here is a simple illustration of the process that we have to go through to make a HTTP POST.

SilverlightHTTPPost

Before we get into code snippets for actually accomplishing the above, let’s get into a little bit of why the above needs to happen. When the user initiates an UI event (button click etc) upon which we must make the HTTP request, we need to ask Silverlight/browser to open a HTTP request pipe to the specified URL. We get this request stream in a different non-UI thread. The reason for this being that Silverlight makes HTTP requests through the browser stack (Silverlight 3 can use its own HTTP stack if needed, but uses the browser stack by default). As you might know, browsers limit the number of outgoing HTTP requests to a given domain name. This limit used to be 2 but modern day browsers have increased this limit (8 in IE8 etc). So, given this limit on the outgoing HTTP requests, there is no guarantee that the browser can open a HTTP request pipe to the URL when demanded by Silverlight. So, we end up getting the request stream in a non-UI thread. We can write/post the necessary data to this request pipe and wait to get a response from the web service. The results from the web service is received on another different non-UI thread. Once we read all the information from the response stream, we can’t start updating the UI elements since we are still on a non-UI thread. So, we need to pass this response from the web service back to the UI thread before we can start updating the UI elements.

Since, we need to pass data between threads as explained above, I had written these tiny little classes to help us through the process of making the HTTP POST request.

 

    public class HttpWebResponseData<T>

    {

        public HttpWebResponse Response { get; set; }

        public T Data { get; set; }

    }

 

    public class HttpWebRequestData<T>

    {

        public HttpWebRequest Request { get; set; }

        public T Data { get; set; }

    }

 

    public class ExceptionEventArgs : EventArgs

    {

        public Exception ExceptionInfo { get; set; }

 

        public ExceptionEventArgs(Exception ex)

        {

            ExceptionInfo = ex;

        }

    }

 

    public class EventArgs<T> : EventArgs

    {

        private T eventData;

 

        public EventArgs(T eventData)

        {

            this.eventData = eventData;

        }

 

        public T EventData

        {

            get

            {

                return eventData;

            }

        }

    }

 

We need to store away the SynchronizationContext of the UI thread before we begin making the HTTP POST request and start jumping threads. This is so that we can get back on the UI thread when the HTTP POST web service call has returned. So, create a variable to hold the in the SynchronizationContext Silverlight UserControl.

        SynchronizationContext syncContext;

 

The following code snippet illustrates how to use the HTTPWebRequest and the HTTPWebResponse classes in Silverlight to perform the HTTP POST.

    //This method will called on user action (button click etc); We are on the UI thread

    private void DoHTTPPost(List<string> stuffToPost)

    {

        //Obtain and store away the SynchronizationContext of the UI thread in the private variable declared above

        syncContext = SynchronizationContext.Current;

        HttpWebRequest request = ( HttpWebRequest ) WebRequest.Create( “URL address to POST to” ) );

        request.Method = “POST”;

        request.ContentType = “text/xml”;

        request.BeginGetRequestStream( new AsyncCallback( DoHTTPPostRequestReady ), new HttpWebRequestData<List<string>>()

        {

            Request = request,

            Data = stuffToPost

        } );

    }

 

    //This method will be called on the non-UI request thread

    private void DoHTTPPostRequestReady(IAsyncResult asyncResult)

    {

        HttpWebRequestData<List<string>> requestData = asyncResult.AsyncState as HttpWebRequestData<List<string>>;

        HttpWebRequest request = requestData.Request;

 

        Stream requestStream = request.EndGetRequestStream(asyncResult);

        DataContractSerializer serializer = new DataContractSerializer(typeof(List<string>));

 

        //Write the string list as XML to the request stream

        StreamWriter sw = new StreamWriter(requestStream);

        serializer.WriteObject(requestStream, requestData.Data);

        sw.Flush();

        requestStream.Close();

 

        request.BeginGetResponse(new AsyncCallback(DoHTTPPostResponseCallback), request);

    }

 

    //This methods will be called on the non-UI response thread

    private void DoHTTPPostResponseCallback(IAsyncResult ar)

    {

        //Ignoring error handling here to keep things simple

        HttpWebRequest request = ar.AsyncState as HttpWebRequest;

        HttpWebResponse response = request.EndGetResponse(ar) as HttpWebResponse;

        Stream responseStream = response.GetResponseStream();

        DataContractSerializer serializer = new DataContractSerializer(typeof(string));

        string result = serializer.ReadObject(responseStream) as string;

 

        //Post the response from the web service back to the UI thread using the SynchronizationContext obtained when initiating the HTTP POST request

        syncContext.Post(DoHTTPPostExtractResponse, new HttpWebResponseData<string>()

        {

            Response = response,

            Data = result

        });

    }

 

    //We are back on the UI thread when this method is called

    private void DoHTTPPostExtractResponse(object state)

    {

        string response = (state as HttpWebResponseData<string>).Data;

        //We can update the UI elements with the response here since we are back on the UI thread

        txtBox.Text = response;

    }

 

I will be posting more helper methods for the above pretty soon. Also, I will delve more into making HTTP POST requests to WCF REST endpoints in future posts.

Generics support in XAML

Posted in C#, Silverlight by viswaug on March 31, 2009

Support for creating generic classes in XAML is still lacking. The only XAML element that lets you specify the generic type argument is only the root element of the user control. I couldn’t find any way to create an instance of a generic class in XAML yet. One had a class called “NameValue” in the project and wanted to be able to create an ObservableCollection<NameValue> in XAML. The only way I was able to do it in XAML was to create another empty class called NameValueCollection that inherited from ObservableCollection<NameValue> and then create an instance of the “NameValueCollection” in XAML instead.

public class NameValueCollection : ObservableCollection<NameValue>
{
}

I think one way generics could be supported in XAML is by creating new MarkupExtensions for that purpose.

Inserting spatial data in SQL Server 2008

Posted in .NET, C#, GIS by viswaug on September 29, 2008

I have been working on inserting data from FeatureClasses into SQL Server 2008 tables. There are a lot of examples online showing how spatial data can be inserted into SQL Server 2008 tables. Here is one from Hannes.

I took from cue from there and proceeded to do what every good programmer should do…parameterize the INSERT query. Here is a simplified version of the scenario I was trying to tackle…

sqlCommand.CommandText = INSERT INTO foo (id, geom) VALUES(1,@g);

sqlCommand.InsertParameter(“@g”, ‘POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))’);

The above INSERT command worked fine. But I also wanted to insert the geometry or geography with the WKID value from the FeatureClass. So I changed the above INSERT statement to use the geometry’s static method and provided the WKID as below

sqlCommand.InsertParameter(“@g”, ‘geometry::STGeomFromText(POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0)), 0)’);

But that didn’t go quite as expected. The INSERT statement was throwing an error saying that it did not recognize ‘geometry::STGeomFromText’ and was expecting ‘POINT, POLYGON, LINESTRING…’ etc.

System.FormatException: 24114: The label geometry::STGeomFrom in the input well-known text (WKT) is not valid. Valid labels are POINT, LINESTRING, POLYGON, MULTIPOINT, MULTILINESTRING, MULTIPOLYGON, or GEOMETRYCOLLECTION.

This led me to use the Udt SqlParamter type to get around the problem like below. This way I could use the SqlGeometry type in the ‘Microsoft.SqlServer.Types’ namespace and set the SRID directly on its ‘STSRID’ property. The ‘SqlGeometry’ and ‘SqlGeography’ types can be found in the Feature Pack for SQL Server 2008 that can be found here. The SqlGeometry reference can then be used as the value for the SqlParameter.

SqlParameter parameter = new SqlParameter( parameterName, value );

parameter.Direction = ParameterDirection.Input;
parameter.ParameterName = parameterName;
parameter.SourceColumn = sourceColumn;
parameter.SqlDbType = SqlDbType.Udt;
parameter.UdtTypeName = “GEOMETRY”;
parameter.SourceVersion = DataRowVersion.Current;

command.Parameters.Add( parameter );

The ‘UdtTypeName’ should be set to ‘GEOGRAPHY’ for inserting geography fields.

And it worked like a charm.

Update: Heard from Morten saying that using the SqlGeography and SqlGeometry types are almost twice as fast as using WKB (Well Known Binary). Using WKB is by itself faster than using WKT (Well Known Text).

Tagged with:

Simulating properties on a bindable list using ITypedList

Posted in .NET, C#, DataBinding by viswaug on August 29, 2007

In this blog post I am going to illustrate how to simulate properties on a bindable list using the ITypedList interface. The ITypedList interface is used by the .NET data-binding mechanism to discover the properties of the items in the list that is being bound. So in fact the ITypedList interface can be implemented by custom collections to customize the properties available for binding on the object to bind to. The .NET data-binding mechanisms use the GetItemProperties(…) method on the ITypedList interface to obtain a PropertyDescriptorCollection to obtain the list of properties available on the object in the list. So, the GetItemProperties(…) method can be overridden to return a custom collection of properties that will be used for data-binding.

Let us take for example, the ‘Distance’ class given below.

    public class Distance

    {

        double _tolerance = 0;

        esriUnits _units = esriUnits.esriFeet;

 

        public Distance(){}

 

        public Distance(double ptolerance, esriUnits punits)

        {

            _tolerance = ptolerance;

            _units = punits;

        }

 

        public double Tolerance

        {

            get { return _tolerance; }

            set { _tolerance = value; }

        }

 

        public esriUnits Units

        {

            get { return _units; }

            set { _units = value; }

        }

 

    }

 

The ‘Distance’ class above contains a tolerance measure and its units as it is public properties. Let’s say that we also have a typed collection ‘DistanceCollection’ of the ‘Distance’ objects.

    public class DistanceCollection

    {

 

        #region “CollectionBase Members”

 

        public Distance this[int index]

        {

            get

            {

                return ((Distance)List[index]);

            }

            set

            {

                List[index] = value;

            }

        }

 

        public int Add(Distance value)

        {

            return (List.Add(value));

        }

 

        public int IndexOf(Distance value)

        {

            return (List.IndexOf(value));

        }

 

        public void Insert(int index, Distance value)

        {

            List.Insert(index, value);

        }

 

        public void Remove(Distance value)

        {

            List.Remove(value);

        }

 

        public bool Contains(Distance value)

        {

            // If value is not of type Distance, this will return false.

            return (List.Contains(value));

        }

 

        protected override void OnInsert(int index, Object value)

        {

            // Insert additional code to be run only when inserting values.

            if (value.GetType() != typeof(Distance))

                throw new ArgumentException(“value must be of type Distance.”, “value”);

        }

 

        protected override void OnRemove(int index, Object value)

        {

            // Insert additional code to be run only when removing values.

            if (value.GetType() != typeof(Distance))

                throw new ArgumentException(“value must be of type Distance.”, “value”);

        }

 

        protected override void OnSet(int index, Object oldValue, Object newValue)

        {

            // Insert additional code to be run only when setting values.

            if (oldValue.GetType() != typeof(Distance))

                throw new ArgumentException(“oldValue must be of type Distance.”, “value”);

 

            if (newValue.GetType() != typeof(Distance))

                throw new ArgumentException(“newValue must be of type Distance.”, “value”);

        }

 

        protected override void OnValidate(Object value)

        {

            if (value.GetType() != typeof(Distance))

                throw new ArgumentException(“value must be of type Distance.”, “value”);

        }

 

        #endregion

 

    }

 

A new datasource could be added in Visual Studio for the ‘DistanceCollection’ type as shown below…

SimulateProperty1

SimulateProperty2

SimulateProperty3

SimulateProperty4

SimulateProperty5

SimulateProperty6

Our goal is to simulate a property called ‘ToleranceInMeters’ on the ‘DistanceCollection’ type so that we have an additional column on the DataGridView specifying the tolerance in meters. In order to achieve this we implement ITypedList on the ‘DistanceCollection’ type and override the GetItemProperties(…) method so that it returns a PropertyDescriptorCollection object with an added PropertyDescriptor object for the ‘ToleranceInMeters’ property.

To return an additional property in the PropertyDescriptorCollection that returns the tolerance in meters, we create a new class called ‘ToleranceInMetersPropertyDescriptor’. And in the GetValue(…) method of the new class we implement the logic to convert the tolerance value from the existing units into meters. In the below code, the ‘ToleranceInMetersPropertyDescriptor’ class has been implemented as an inner class inside ‘DistanceCollection’. We also build the new PropertyDescriptorCollection in the static constructor of ‘DistanceCollection’ and return it inside the GetItemProperties(…) method.

 

    public class DistanceCollection : CollectionBase, ITypedList

    {

 

        static DistanceCollection()

        {

            CalculatePropertyDescriptors();

        }

 

        #region “CollectionBase Members”

 

        public Distance this[int index]

        {

            get

            {

                return ((Distance)List[index]);

            }

            set

            {

                List[index] = value;

            }

        }

 

        public int Add(Distance value)

        {

            return (List.Add(value));

        }

 

        public int IndexOf(Distance value)

        {

            return (List.IndexOf(value));

        }

 

        public void Insert(int index, Distance value)

        {

            List.Insert(index, value);

        }

 

        public void Remove(Distance value)

        {

            List.Remove(value);

        }

 

        public bool Contains(Distance value)

        {

            // If value is not of type Distance, this will return false.

            return (List.Contains(value));

        }

 

        protected override void OnInsert(int index, Object value)

        {

            // Insert additional code to be run only when inserting values.

            if (value.GetType() != typeof(Distance))

                throw new ArgumentException(“value must be of type Distance.”, “value”);

        }

 

        protected override void OnRemove(int index, Object value)

        {

            // Insert additional code to be run only when removing values.

            if (value.GetType() != typeof(Distance))

                throw new ArgumentException(“value must be of type Distance.”, “value”);

        }

 

        protected override void OnSet(int index, Object oldValue, Object newValue)

        {

            // Insert additional code to be run only when setting values.

            if (oldValue.GetType() != typeof(Distance))

                throw new ArgumentException(“oldValue must be of type Distance.”, “value”);

 

            if (newValue.GetType() != typeof(Distance))

                throw new ArgumentException(“newValue must be of type Distance.”, “value”);

        }

 

        protected override void OnValidate(Object value)

        {

            if (value.GetType() != typeof(Distance))

                throw new ArgumentException(“value must be of type Distance.”, “value”);

        }

 

        #endregion

 

        #region “Simulated Property”

 

        private class ToleranceInMetersPropertyDescriptor : PropertyDescriptor

        {

            UnitConverterClass _converter = new UnitConverterClass();

 

            public ToleranceInMetersPropertyDescriptor(string name)

                : base(name, null)

            {

 

            }

 

            public override bool CanResetValue(object component)

            {

                return false;

            }

 

            public override System.Type ComponentType

            {

                get { return typeof(Distance); }

            }

 

            public override bool IsReadOnly

            {

                get { return true; }

            }

 

            public override System.Type PropertyType

            {

                get { return typeof(double); }

            }

 

            public override void ResetValue(object component)

            {

 

            }

 

            public override object GetValue(object component)

            {

 

                Distance d = (Distance)component;

                return _converter.ConvertUnits(d.Tolerance, d.Units, esriUnits.esriMeters);

            }

 

            public override void SetValue(object component, object value)

            {

 

            }

 

            public override bool ShouldSerializeValue(object component)

            {

                return false;

            }

        }

 

 

        #endregion

 

        #region ITypedList Members

 

 

        private static PropertyDescriptorCollection propertyDescriptors;

 

        PropertyDescriptorCollection ITypedList.GetItemProperties(PropertyDescriptor[] listAccessors)

        {

            return propertyDescriptors;

        }

 

        string ITypedList.GetListName(PropertyDescriptor[] listAccessors)

        {

            return “DistanceCollection”;

        }

 

        private static void CalculatePropertyDescriptors()

        {

            PropertyDescriptorCollection origProperties = TypeDescriptor.GetProperties(typeof(Distance));

            ArrayList properties = new ArrayList();

            foreach (PropertyDescriptor desc in origProperties)

            {

                properties.Add(desc);

            }

            properties.Add(new ToleranceInMetersPropertyDescriptor(“ToleranceInMeters”));

            propertyDescriptors = new PropertyDescriptorCollection((PropertyDescriptor[])properties.ToArray(typeof(PropertyDescriptor)));

        }

 

        #endregion

 

    }

 

What do you achieve by all this? Well, we get a property on the ‘DistanceCollection’ type in the Data Sources window in Visual Studio 2005 and when it is dragged on to the form the DataGridView now appears with a an additional column called ‘ToleranceInMeters’.

SimulateProperty7

In the constructor of the form, initialize the binding source for the DistanceCollection and the result will be what you see below.

 

DistanceCollection _Coll = new DistanceCollection();

_Coll.Add(new Distance(1, ESRI.ArcGIS.esriSystem.esriUnits.esriFeet));

_Coll.Add(new Distance(1, ESRI.ArcGIS.esriSystem.esriUnits.esriInches));

_Coll.Add(new Distance(1, ESRI.ArcGIS.esriSystem.esriUnits.esriKilometers));

_Coll.Add(new Distance(1, ESRI.ArcGIS.esriSystem.esriUnits.esriMiles));

_Coll.Add(new Distance(1, ESRI.ArcGIS.esriSystem.esriUnits.esriNauticalMiles));

_Coll.Add(new Distance(1, ESRI.ArcGIS.esriSystem.esriUnits.esriDecimalDegrees));

distanceCollectionBindingSource.DataSource = _Coll;

SimulateProperty8