The Box

Posted on Tuesday 28 October 2008

I enjoyed reading Al’s post on travelling :-) I’ve been doing plenty of it over the past two and half years!

Last night I flew back from Canberra. To a soundtrack of Tiny Dancer I looked down on Melbourne which looked like a map  - the road lights dissecting the city at night - it was really cool and made the long day worth while.

While we travel around the globe - think about The Box and where it might be?

mapbutcher @ 7:24 pm
Filed under: porterhouse
ArcGIS Server REST API, OpenLayers and some potatoes

Posted on Tuesday 7 October 2008

I recently had a short but humorous conversation with James Fee about my lament for AXL, James suggested that JSON offers some real advantages over AXL which got me thinking….

Fast forward to a few days later, a friend of mine is showing me the ArcGIS Server Flex API which provides some rather nice vector management based upon JSON returns from the ArcGIS Server REST API…….

Fast forward to that evening, i’m chatting with someone else about a potential Integration showcase at FOSS4G2009…..

Fast forward to late last night..

So i’d had a glass of wine or two and thought that i’d boil some potatoes  - why because i’m busy and I have a hungry little boy who doesn’t like waiting for his dinner when he comes home (…i used to be a scout..be prepared!) While the potatoes came to the boil I began some map butchery.

OpenLayers handles vectors rather nicely and the ArcGIS Server REST API can return geometry - ESRI and Opensource integration, can’t be that hard - here’s a small recipe based on the existing OpenLayers vector sample  (excuse the hacks - i did say there was wine involved)

Pre-requisites:

1. ArcGIS Server 9.3 - with service running
2. Some wine
3. Some boiling potatoes
4. No consideration for code

1. So the REST API has a Query Layer operation a typical call to this operation might be:

http://localhost/ArcGIS/rest/services/worldadmin/MapServer/0/query?text=&geometry=&geometryType=esriGeometryEnvelope&inSR=&spatialRel=esriSpatialRelIntersects&where=%22FIPS_CNTRY%22+%3D+%27AS%27&returnGeometry=true&outSR=4326&outFields=&f=json

Some things which are worth noting here is that I’m using a where clause in my query (where=[FIPS_CNTRY]=’AS’) and also I am specifying the output spatial reference as 4326 - which happens to be WGS 1984 which will mean my geometries will match the base map in OpenLayers and finally the format as JSON- ESRI offers a f-pjson format which is handy for inspecting the JSON.

2. Now we need to create a JSON object based upon our ArcGIS Server REST call above:

	//create esri JSON object
	var myReturn = "esriObj = "+xmlHttpGet(restCall, false);
	eval(myReturn);

I can now work with esriObj as a JSON object i.e. esriObj.geometryType. What happens in the xmlHttpGet method? Basically I create a XMLHttpRequest and pass in my REST URL - your can see this code here

3. OK i have my ‘ESRI query’ JSON object now I need to parse the features in this object and essentially create GeoJSON strings which the OpenLayers sample will be happy with - cue the code butchery…

 
function esriDeserialize(geojson)
{
 
	var element = document.getElementById('text');
	var type = document.getElementById("formatType").value;
	var features = formats['in'][type].read(geojson);
	var bounds;
	if(features)
	{
		if(features.constructor != Array) {
			features = [features];
		}
		for(var i=0; i<features.length;>
			if (!bounds) {
				bounds = features[i].geometry.getBounds();
			} else {
				bounds.extend(features[i].geometry.getBounds());
			}
 
		}
		vectors.addFeatures(features);
		//map.zoomToExtent(bounds);
		var plural = (features.length &gt; 1) ? 's' : '';
		//element.value = features.length + ' feature' + plural + ' added'
	} else {
		element.value = 'Bad input ' + type;
	}
}
 
function getEsriGeom(restCall){
 
	//call ESRI Rest API
	//"http://pc302926/ArcGIS/rest/services/worldadmin/MapServer/0/query?text=&amp;geometry=&amp;geometryType=esriGeometryEnvelope&amp;inSR=&amp;spatialRel=esriSpatialRelIntersects&amp;where=%22FIPS_CNTRY%22+%3D+%27AS%27&amp;returnGeometry=true&amp;outSR=4326&amp;outFields=&amp;f=json"
	var element = document.getElementById('text');	
 
	//create esri JSON object
	var myReturn = "esriObj = "+xmlHttpGet(restCall, false);
	eval(myReturn);
 
    element.value = "";
	var coordPairsPerFeature = 0;
 
	//for each feature
	for (var i=0; i &lt; esriObj.features.length; i++)
	{
		//get the geometry
		var o = esriObj.features[i].geometry;
		element.value = element.value + esriObj.features[i].attributes.ADMIN_NAME;
 
		//loop through all the rings
		for (var s=0; s &lt; o.rings.length; s++)
		{
			//create geojson start &amp; end - i know i'm getting polygons
			var geojsonstart = '{"type":"Feature", "id":"OpenLayers.Feature.Vector_124", "properties":{}, "geometry":{"type":"Polygon", "coordinates":[['
			var geojsonend = ']]}, "crs":{"type":"OGC", "properties":{"urn":"urn:ogc:def:crs:OGC:1.3:CRS84"}}}';
 
			//the coordinates for this ring
			var coords = o.rings[s];
 
			//loop through each coordinate
			var coordPair="";
			for (var g=0; g &lt; coords.length; g++)
			{
			    coordPairsPerFeature = coordPairsPerFeature+1;
 
				//alert(coords[g]);
				if(g==coords.length-1){
					coordPair = coordPair+"["+coords[g]+"]";
				}else{
					coordPair=coordPair+"["+coords[g]+"],";
				}
			}
 
			//combine to create geojson string
			esriDeserialize(geojsonstart+coordPair+geojsonend);
		}
 
		element.value = element.value + "," + coordPairsPerFeature +"n";
	}
 
}
</features.length;>

4. Finally I call esriDeserialize which is just an amended version of the OpenLayers sample Deserialize method which does not update the text box (i do that during the previous method in the stack with the number of vertices’s per geometry) and does not refresh the map after each addition of the OpenLayers vectors. The video below shows OpenLayers rendering all the US states polygons via the ArcGIS Server REST API -315, 984 vertices.

 

Post-requisites

1. Forget about potatoes
2. Go to bed
3. Wake up 7 hrs later due to strong smell of burning potatoes
4. Go back to sleep
5. Wake up 1 hr later with a sudden realisation that i was trying to be prepared…!

The code can be downloaded from here

mapbutcher @ 8:12 pm
Filed under: porterhouse
FOSS4G……2009

Posted on Tuesday 30 September 2008

FOSS4G2009
Yeh we finally got the site up today - hope everyone is having a good time in Cape Town

mapbutcher @ 8:52 pm
Filed under: chuck
A lament for AXL

Posted on Monday 22 September 2008

Over the past few weeks I have been switching between working with ArcGIS Server and ArcIMS. As a consequence of this I’ve been thinking more and more about AXL and its role in defining maps for a generation of ArcIMS web mapping applications. For those that don’t know, ArcXML or AXL is a protocol for dealing with ArcIMS Spatial Servers, it is also used for defining map services within ArcIMS. Because it’s XML anybody can read and interpret and for that matter create AXL files that represent a configuration for the map which you want ArcIMS to serve. No one said the process of creating and managing AXL files was painless, it is anything but (to a beginner), but anybody could create an AXL file and this is a very important point.

A little while after ArcIMS appeared a new type of service was introduced - ArcMap Image Services, these differ from standard ArcIMS Image Services as they use the proprietary map document format from ESRI to author the map service. Now there was no doubt valid motivation for this and it assists GIS administrators by linking their desktop authored map documents directly to Internet mapping services. Many people stuck with AXL configuration - it was faster, they had grown used to it and didn’t see the need to use desktop GIS software to create map configuration files, some people even created converters which converted the map document files (mxd’s) into AXL files so you could have the best of both worlds.

Then ArcGIS Server came along, brilliant, we can leverage all that rich GIS goodness from ArcObjects on the server, but what about creating map services? How do i do that? Well to create a map service, and expose its contents and functionality (including the useful geoprocessing framework functionality) I need to create a map document. Is there another way? Not that I know of. So suddenly I’m coupled to my desktop GIS. The core way in which a map is configured for viewing is tightly integrated into the ESRI GIS desktop software, I can’t export my map document to a humanly readable configuration. The service understands the map document file, reads it upon service creation and then does not use it again (until the service needs to be amended and restarted i.e. the addition of a new map layer)

It doesn’t matter how much i hated AXL i still recognise its openness and whilst ESRI continues to support open standards I really would like to see the ability to be able to create my own map configurations without the need for a desktop GIS seat. But why - why hack at AXL when you can use a swish desktop mapping software to set up layers, complex symbology, queries, geoprocessing tools etc? Well here are a number of reasons INHO:

  • AXL provides a transparent and open protocol
  • Because AXL was open anybody could create an AXL files or AXL editors as long as they understood the protocol
  • That same openness, promotes choice for users
  • I never had an AXL file crash on me or even worse crash and become corrupt as a result of the crash (even with MXDDoctor you could still loose a lot of work)
  • AXL helped me understand what was beneath a map service, map documents obscure that, in much the same way IDE’s obscure the complexity of WSDL creation for example, but to understand SOAP services you really should spend some time understanding the WSDL definition

I’m not crying over spilt milk here, the last thing i really want to do is spend an afternoon crafting XML to get a map with 5 layers one of which is blue….I use ESRI Desktop GIS to create my map configurations every-time, but i have no choice so I just put my trust in the black box.

mapbutcher @ 8:33 am
Filed under: flank
Using ILogSupport for your Server Object Extension

Posted on Monday 22 September 2008

Following on from my last post I thought I’d touch quickly on using the in built logging functionality of ArcGIS Server. This post is within the context of Server Object Extensions (SOE).

When using SOE’s you implement a number of interfaces:

  • ESRI.ArcGIS.esriSystem.IObjectConstruct
  • ESRI.ArcGIS.Server.IServerObjectExtension
  • ESRI.ArcGIS.esriSystem.ILogSupport

There are a number of other classes which implement ILogSupport more info here  Typically you may wish to initialise a local log object and this can be done via the InitLogging method of the ILogSupport Interface

private ESRI.ArcGIS.esriSystem.ILog2 m_log;
 
public void InitLogging(ESRI.ArcGIS.esriSystem.ILog Log)
{
m_log = (ESRI.ArcGIS.esriSystem.ILog2)Log;
}

Note that I am using the ILog2 Interface as it offers a little bit more than ILog - so i have to cast one to the other.

Ok now i have my local log object I can fire entries into the log as needed -  When my SOE initialises I create a set of objects ready for use by the SOE methods, AGS automatically logs server object construction within the server log, so strictly speaking this is not really a good example, but it illustrates the point hopefully.

public void Construct(ESRI.ArcGIS.esriSystem.IPropertySet props)
{
...
m_log.AddMessageEx(3, "LrsServerObjectExt.Construct", 110000, 0.0, "SOE objects initialised sucessfully");
..
}

So at the end of the Construct() method on the SOE I create an entry into the log. I’m using a message code out of range of the ESRI codes (110000) and i’m logging an information message using the message type 3 - (error:1, warning:2, info:3, detailed:4, debug:5).

Now that the log has been made I can validate this using the AGS Manager application - which has an improved interface for viewing logs at version 9.3:

ArcGIS Server Manager

Easy.

mapbutcher @ 8:02 am
Filed under: rib