Blog

Open Source GIS experiences

26 Aug, 2009
Xebia Background Header Wave

After being away from the GIS world for a while, I started working on a new project replacing the current used software by an open source alternative. The first small application that needed to be made was for an emergency phone call center to show the position of the caller on a map. After that a few prototypes should prove that it was doable to replace the current software stack by open source alternatives.
In this blog I will describe the tools used, a few of the problems I ran into and of course the solutions to the problems which involve coding and communication 😉

The tools used where a Java based server called Geoserver and a client side JavaScript library called OpenLayers.

Geoserver

GeoServer is a server that allows users to share and edit geospatial data. It is the implementation of the Open Geospatial Consortium (OGC) Web Feature Service (WFS) and Web Map Service (WMS) standards.

WMS

A Web Map Server publishes maps. In short it is used to create pictures from all kinds of different spatial sources like databases (for example postgis, oracle spatial), files (like esri shapefiles, GML (Geography Markup Language), MapInfo) etc. It can also be used to get some extra information stored with the geographical data.

WFS

A Web Feature Server is an interface to get, supply or change geographical vector data. It uses the GML format to communicate between client and server.

OpenLayers

OpenLayers is an open source JavaScript library for displaying geographical data in a rich web environment, the API can be used to create Google Maps like applications.

Challenges

In my current assignment I faced a few challenges in different parts of the application. In the next part of this blog I’d like to explain the solutions I used. I hope someone will benefit from this. With each solution i will also explain some of the surrounding techniques used within the GIS domain.

Reprojection

One of the problems in the application showing the position of the mobile caller was the accuracy of the position. The position data was provided in WGS84 (world geodetic system) This coordinate reference system is also used for GPS coordinates. But because the coordinates needed to be put on a map of the Netherlands which was in a different coordinate reference (RD) the coordinates needed to be transformed (this is called reprojection).

Transforming between two coordinate systems involves difficult mathematic formulas, but OpenLayers is prepared to use the Proj4js library which simplifies this for you a lot.

So with a simple statement like this you can transform between 2 different projections:

  //transform from wgs84 to rijksdriehoeks  28992
  markerLocation =new OpenLayers.LonLat(x,y);
  markerLocation.transform(new OpenLayers.Projection('EPSG:4326'),
                           new OpenLayers.Projection('EPSG:28992'));

The catch here was that the definition for the EPSG:28992 projection needed to be accurate to be able to put the marker at the correct possition. In our case the +to_wgs part of the definition mattered a lot!

Proj4js.defs['EPSG:28992'] = '+title=Amersfoort / RD New EPSG:28992
                              +proj=sterea
                              +lat_0=52.15616055555555 +lon_0=5.38763888888889
                              +k=1.0
                              +x_0=155000 +y_0=463000
                              +ellps=bessel
                              +towgs84=565.,49.9,465.8,-0.409,0.36,-1.869,4.08
                              +units=m';
Showing current position

Another application was developed to show the position of cars on the map of the Netherlands. With the right configuration of Geoserver and a WFS Layer in OpenLayers this was not that difficult. At least not at first sight.

Problem here was that the positions where update in the database every 5 seconds so the view from the browser needed to be refreshed every 5 seconds also.

layer.refresh({force: true});

Not much code for such functionality, and it worked. At least for about 30 minutes until the browser crashed on me. What?

It seemed that the browser was taking more and more memory after each refresh. So somewhere there was a Memory Leak. It turned out to be because of the way OpenLayers draws its elements on the page. It is done by DOM manipulation (element.appendChild and element.removeChild).

The problem is that the removeChild method removes the child from the visual space but keeps a reference in memory. This reference can be used to retrieve the element again and show it (because you accidently removed it??). This memory space is only garbage collected when a new page is opened. But nowadays Ajax like applications don’t open a new page so hence the memory leak.

For IE (the browser used) this is by design so hope that a fix will be around in newer versions is zero.

Luckily a workaround exists which helps to limit the Memory Leak.

Workaround
OpenLayers.Util.discardElement = function(element) {
  var garbageBin = document.getElementById('IELeakGarbageBin');
  if (!garbageBin) {
    garbageBin = document.createElement('DIV');
    garbageBin.id = 'IELeakGarbageBin';
    garbageBin.style.display = 'none';
    document.body.appendChild(garbageBin);
  }
  // move the element to the garbage bin
  try {
    garbageBin.appendChild(element);
  }
  catch(e) {
    //do nothing
  }
  garbageBin.innerHTML = '';
  if (element.removeNode) element.removeNode(false);
  //delete element;
};
Distance calculation

On to the next challenge. One of the requirements was that all markers within a certain distance of a region would be visible. Imagine such a region consisting of 40.000+ points. So to determine if a point lies within say 10kilometers from that region is not an easy calculation. The Oracle Spatial database has a function to do this but to do this for all markers was not performing fast enough (remember that the client was refreshed every 5 seconds!)

The solution here was to change the requirement a bit and to show only the markers within a certain distance of a point. This was an easy calculation and could be done with supplying a query to the geoserver request

complex types

Next problem was the use of complex geometries. oracle spatial has support for curves and stuff, but geoserver can only read simple geometry types like points, linestrings, polygons, multilinestrings, multipolygons.

Lucky i was to find that within the definition of a complex geometry also is encapsulated a simple geometry. All that was needed was a little code to extract that simple geometry from the complex one and voila:

Heres the code snippet:

        if ((L == 0) && (TT == 01) && (point != null) && (elemInfo == null)) {
            // Single Point Type Optimization
            coords = SDO.coordinates(gf.getCoordinateSequenceFactory(), GTYPE,
                    point);
            elemInfo = new int[] { 1, ETYPE.POINT, 1 };
        } else {
            int element = 0;
            int etype = ETYPE(elemInfo, element);
            if (etype == 0) {
               // complex type, search for encapsulated simpletype (with etype != 0)
               int startpointCoordinates = 0;
               // look for a simple one
               while (etype == 0) {
                   element++;
                   etype = ETYPE(elemInfo, element);
                   startpointCoordinates = STARTING_OFFSET(elemInfo, element);
               }
               // if we found the simple fallback, read it
               if (etype != -1) {
                   int ol = ordinates.length;
                   int elemsToCopy = ol - (startpointCoordinates - 1);
                   double[] newOrdinates = new double[elemsToCopy];
                   System.arraycopy(ordinates, startpointCoordinates - 1, newOrdinates, 0, elemsToCopy);
                   elemInfo = new int[] { 1, etype, INTERPRETATION(elemInfo, element) };
                   ordinates = newOrdinates;
               }
            }
            coords = SDO.coordinates(gf.getCoordinateSequenceFactory(), GTYPE,
                     ordinates);
        }
        return create(gf, GTYPE, SRID, elemInfo, 0, coords, -1);

So far a few of the challenges i came across using OpenSource GIS software. What I’ve noticed is that both the openLayers and Geoserver community are very helpful and that both projects are maturing every release.

Let’s see what the future of this project brings when we need to have the client be available for at least 8 hours in a row. I guess the browser (at least IE) is out of the question. Looking forward to investigate the possibilities of a flex client application.

Questions?

Get in touch with us to learn more about the subject and related solutions

Explore related posts