Saturday, February 18, 2012

NHibernate Spatial (Part 3)


This is the third part of a series of posts regarding a simple example using NHibernate Spatial.


Actually, the title is kind of misleading as this post is just the wrap-up of the previous one, and I will not do much more regarding NHibernate Spatial (at least on this post). I'll just do the web page for the user interaction.

As I said, I'll create a simple map that, when clicked on  a specific point, paints the district that contains it. Not particularly useful but should be easy enough to understand and adapt to a more realistic scenario.


Anyway, in my previous post I had an ASP.NET MVC action that retrieved a polygon based on an hardcoded coordinate using NHibernate. First let's change the action so that the coordinate is received as an argument.

The action code thus becomes:
/// <summary>
/// Gets the district that contains the supplied point
/// </summary>
/// <param name="longitude">Longitude in WGS84 decimal degrees</param>
/// <param name="latitude">Latitude in WGS84 decimal degrees</param>
/// <returns>
/// An object with the district name and an array with the polygon points
/// </returns>
public JsonResult GetDistrictContainingPoint(string longitude, string latitude)
{
    double lat = Convert.ToDouble(latitude, new CultureInfo("en-US"));
    double lon = Convert.ToDouble(longitude, new CultureInfo("en-US"));

    ISession session = NHibernateManager.CurrentSession;
            
    District district = session.QueryOver<District>()
        .WhereSpatialRestrictionOn(d => d.Area)
        .Intersects(new Point(lon, lat))
        .SingleOrDefault();

    var points = district.Area.Coordinates
                         .Select(p => new {longitude = p.X, latitude = p.Y})
                         .ToArray();
    return Json(new { district.Id, district.Name, Points = points});
}

Now, we're just missing the Javascript code to handle the click event on the map and fetch the polygon coordinates based on the click point.
The full source for the ASP.NET MVC View is:
@model dynamic
@{
    Layout = null;
}
<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>NHibernate Spatial Test</title>

    <script type="text/javascript" src="jquery-1.4.2.js"></script>

    <script type="text/javascript">

        var bingMaps = 
            'http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0';

        $(function () {

            var MM;
            var map;

            $.ajax({
                url: bingMaps ,
                dataType: 'jsonp',
                jsonp: 'onscriptload',
                success: function (data) {

                    MM = Microsoft.Maps;

                    map = new MM.Map($('#mapDiv')[0], {
                        credentials: "BING MAPS KEY GOES HERE",
                        showCopyright: false,
                        showDashboard: false,
                        mapTypeId: MM.MapTypeId.road,
                        showLogo: false,
                        showMapTypeSelector: false,
                        showScalebar: false,
                        center: new MM.Location(39.5, -8.5),
                        zoom: 7
                    });

                    MM.Events.addHandler(map, 'click', getDistrict);     
                }
            });
        });

        function getDistrict(e) {

            var point = new MM.Point(e.getX(), e.getY());
            var loc = e.target.tryPixelToLocation(point);

            $.post('Spatial/GetDistrictContainingPoint', { 
                longitude: loc.longitude, 
                latitude: loc.latitude }, 
                function (data) {

                    var polygonPoints = new Array();

                    for (var i = 0; i < data.Points.length; i++) {

                        var polygonPoint = new MM.Location(
                            data.Points[i].latitude, 
                            data.Points[i].longitude);

                        polygonPoints.push(polygonPoint);
                    }
                    var polygoncolor = new MM.Color(150, 100, 50, 50);
                    var polygon = new MM.Polygon(
                        polygonPoints, { 
                            fillColor: polygoncolor, 
                            strokeColor: polygoncolor });

                    map.entities.push(polygon);
                });
            }

    </script>
</head>
<body>
    <div id="mapDiv" class="map"/>
</body>
</html>

After running the example we get a nice empty map that paints the districts that are clicked upon.


NHibernate Spatial is really useful but it still has several limitations, particularly in the spatial operations that it provides.

If oportunity comes I'll do a post on how to extend NHibernate Spatial and develop our own Spatial Operation to be used in QueryOver.


Go to Part 4

No comments:

Post a Comment