Smathermather's Weblog

Remote Sensing, GIS, Ecology, and Oddball Techniques

Posts Tagged ‘Geoserver’

Take that, hipsters. Compositing in GeoServer

Posted by smathermather on February 12, 2015

Let’s be honest. There’s some un-coolness to GeoServer. It’s built on Java. It’s old(er) and multi-purpose. It has none of the cache of server side javascript or GoLang goodness. But bless me, it is a workhorse. And sometimes having a tool that can do anything is a blessing. If multi-purpose toolbelts and pocket protectors are uncool, then declare me uncool. You won’t be the first.

Anyway, this a long way of saying that GeoServer now has something that the Mapnik ecosystem has — it has compositing! Which means any cartographic effect you want is well within reach with GeoServer.

Examples of compositing in GeoServer

So, now you can do “Enterprise” geo stuff _with_compositing. Cheers.

http://docs.geoserver.org/latest/en/user/styling/sld-extensions/composite-blend.html

http://blog.geoserver.org/2015/01/22/geoserver-2-7-beta-released/

Posted in GeoServer | Tagged: , | 2 Comments »

Serving and filtering #GeoJSON from #GeoServer

Posted by smathermather on July 19, 2012

The nice thing about setting up something like GeoServer, which is so feature rich, is when you need to pivot based on the demands of a new project, the technical infrastructure is already there, just waiting to be configured or turned on.

The case today: feature services.  Someone wants to use my existing infrastructure in a new application.  I typically serve tile services.  One checkbox to enable WFS; a couple clicks to see an example GeoJSON request, and

http://localhost:8080/geoserver/cm/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=cm:parks&outputFormat=json

Ah.  That wasn’t so bad.  But wait, we need to filter the request!  GeoServer offers CQL and ECQL:

http://localhost:8080/geoserver/cm/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=cm:parks&outputFormat=json&cql_filter=(res=’Mildreds Favorite Park”)

Oops, I also need it reprojected on the fly to Google Mercator:

http://localhost:8080/geoserver/cm/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=cm:parks&outputFormat=json&cql_filter=(res=’Mildreds Favorite Park”)&srsName=EPSG:3857

Not too bad for a feature I hadn’t needed until today… .

Posted in GeoServer | Tagged: , , , , | 1 Comment »

GeoServer and efficient delivery of raster data (image pyramid layer) (update)

Posted by smathermather on May 11, 2012

A perennial favorite on this blog is “GeoServer and efficient delivery of raster data (image pyramid layer)“. I am neither the last nor the first authority on this topic (check the GeoSolutions blog for authoritative work on GeoServer and raster, also look to the GeoServer documentation), but I’ve had some good experiences with serving rasters in GeoServer, especially using image pyramid layers

Read the original, as this will just augment, but here are some targets to hit with the retiling necessary for larger datasets. This is the command I currently use for the retiling:


gdal_retile.py -v -r bilinear -levels 4 -ps 6144 6144 -co "TILED=YES" -co "BLOCKXSIZE=256" -co "BLOCKYSIZE=256" -s_srs  EPSG:3734 -targetDir aerial_2011 --optfile list.txt

Don’t be afraid of big block sizes. Bump your memory up in your application container, stop worrying and learn to love the larger tif. I keep my total number of output tifs to no more than 2000, where I start to see performance issues in my implementation.
Also, give the image pyramid code a break. After retiling, do this:

mkdir 0
mv *.tif 0/.

Posted in GeoServer, GeoWebCache | Tagged: , , , , | 1 Comment »

Advanced Cartography in #GeoServer– #SLDs can make for very pretty maps

Posted by smathermather on May 10, 2012

I said it in the title, I’ll say it again, SLDs are not just for ugly maps.

I’ve heard from several professionals in this geospatial sector that CartoCSS is so cool– “look at the great cartography you can get out of it”. And, truth be told, creating a standard for cartography that aligns so well with existing web development standards is a brilliant way to get designers in on the map development process (as demonstrated aptly by e.g. Stamen), something sorely needed since Geography decided that cartographers weren’t needed anymore, some time in the late 90s/ early double aughts. That said, and at the risk of sounding parochial, beautiful maps can be produced using SLDs in GeoServer too. The below map is a snapshot from our GeoServer instance, and evolved from a set of cartographic conventions we’ve been developing in our shop, adapted in 4 hours by a darn smart part time employee (Tom Kraft) who had never built an SLD before.

Without further addo:

Posted in GeoServer | Tagged: , , , , | 6 Comments »

OpenLayers, GeoExt, GeoServer, and GetFeatureInfo

Posted by smathermather on May 6, 2012

I wrote an earlier post on using GetFeatureInfo through OpenLayers to bring back a formatted html document with pictures, and formated tables, etc.  It wasn’t sophisticated, but got the job done.  Since around that time, as I’ve been building out our services, the speed with which a GetFeatureInfo request returns has g o t t  e  n  p    r     o     g       r       e        s         s            i             v              e             l            y     slower, to the point where the feature is essentially unusable.  Why?  Poor client coding.  Here’s my getfeatureinfo codeblock for OpenLayers:


////// WMS GetFeatureInfo
var info = new OpenLayers.Control.WMSGetFeatureInfo({
             drillDown : false,
queryVisible : true,
panMapIfOutOfView : false,
             url : GeoserverWMS,
layerUrls : [GeowebcacheURL],
eventListeners : {
getfeatureinfo : function (event) {
popup = new OpenLayers.Popup.FramedCloud(
                             "popinfo",
map.getLonLatFromPixel(event.xy),
null,
event.text,
null,
                             true);
map.addPopup(popup, true);
}
}
});

map.addControl(info);
info.activate();

//  end of popup code

The problem?  This code will query all visible layers.   Lots of visible layers results in a GetFeatureInfo request that looks like this:
localhost:8080/geoserver/wms?&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetFeatureInfo&LAYERS=summer_aerial_2,summer_aerial_1,reservation_boundaries_public_private_cm_dissolved_mask_gradien,odot_interstate,odot_us_routes,odot_state_routes,reservation_bounds,detailed_hydro_view,cm_bridge_view,cm_trails,impervious_update,cm_buildings,cm_buildings_outline,golf_view,nhd_lake_erie,supplementary_shields,planet_osm_line,cuyahoga_street_centerlines_labels,planet_osm_line_outside_cuy,detailed_hydro_labels,facilities_cm,facility_areas_cm&QUERY_LAYERS=summer_aerial_2,summer_aerial_1,reservation_boundaries_public_private_cm_dissolved_mask_gradien,odot_interstate,odot_us_routes,odot_state_routes,reservation_bounds,detailed_hydro_view,cm_bridge_view,cm_trails,impervious_update,cm_buildings,cm_buildings_outline,golf_view,nhd_lake_erie,supplementary_shields,planet_osm_line,cuyahoga_street_centerlines_labels,planet_osm_line_outside_cuy,detailed_hydro_labels,facilities_cm,facility_areas_cm&STYLES=,,,,,,,,,,,,,,,,,,,,,&BBOX=2232424.250515%2C625357.428203%2C2233363.463113%2C625592.231353&FEATURE_COUNT=10&HEIGHT=213&WIDTH=852&FORMAT=image%2Fpng&INFO_FORMAT=text%2Fhtml&SRS=EPSG%3A3734&X=320&Y=91
My naive attempts to fix this were simply adding a layers key/value pair, e.g.:

////// WMS GetFeatureInfo
     var info = new OpenLayers.Control.WMSGetFeatureInfo({
drillDown : false,
queryVisible : true,
panMapIfOutOfView : false,
             url : GeoserverWMS,
layers : [reservation_bounds],
layerUrls : [GeowebcacheURL],
eventListeners : {
getfeatureinfo : function (event) {
                     popup = new OpenLayers.Popup.FramedCloud(
                             "popinfo",
map.getLonLatFromPixel(event.xy),
null,
event.text,
null,
                             true);
map.addPopup(popup, true);
}
}
});

map.addControl(info);
info.activate();

//  end of popup code
… but for whatever reason, maybe the way I instantiated the OpenLayers.Layer.WMS instances using Ext.each (ahem, the way I modified a vendor’s cleverly written code…), the layers aren’t recognized as objects by the name I might expect.  So, I hack and create a duplicate layer by a different name.  I’ll have a non-hack version here soon (I hope) which will use the existing array of WMS instances, loop through them, and only add the appropriate ones to the layers array.  In the mean time, this should work.
var reservation_bounds = new OpenLayers.Layer.WMS("Reservation Boundaries", GeoserverWMS,
{'layers': 'base:reservation_bounds', transparent: true, format: 'image/png'},
             {isBaseLayer: false}
);

////// WMS GetFeatureInfo
var info = new OpenLayers.Control.WMSGetFeatureInfo({
drillDown : false,
queryVisible : true,
panMapIfOutOfView : false,
             url : GeoserverWMS,
layers : [reservation_bounds],
layerUrls : [GeowebcacheURL],
eventListeners : {
getfeatureinfo : function (event) {
popup = new OpenLayers.Popup.FramedCloud(
                             "popinfo",
map.getLonLatFromPixel(event.xy),
null,
event.text,
null,
                             true);
map.addPopup(popup, true);
}
}
});

map.addControl(info);
info.activate();

//  end of popup code

Posted in GeoExt, GeoServer, Javascript, OpenLayers | Tagged: , , , , | Leave a Comment »

Building simple clients for MapFish — cURL as a client

Posted by smathermather on April 25, 2012

I have two previous posts on using MapFish (in this case, the GeoServer version) to allow for printing to hi-resolution PDF maps from the browser.  Here we use a command-line browser (cURL) to post our json to the MapFish service in order to retrieve our PDF.

I did not keep any notes from before on making json posts to the MapFish server as a means by which to test any manual configuration of the json file, so I had to rediscover this approach from pages like this.

The “@” sign below is so that curl knows I’m feeding it a file instead of the actual json to post:


curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X POST --data @mapfish_landscape.json http://localhost:8080/geoserver/pdf/create.json

Posted in Database, GeoExt, GeoExt, GeoServer, MapFish, PostGIS, PostgreSQL, SQL | Tagged: , , , , , , , , , | 3 Comments »

Building simple clients for MapFish — Beginnings of a PL/pgSQL function

Posted by smathermather on March 10, 2012

I’ve had a couple of other posts (1 and 2 and 3 and) on simple clients for MapFish.  I like the client server infrastructure for MapFish– with the client end of things built up in GeoExt, it makes for a really elegant combo.  But I’d like articulate my vision for simple clients for MapFish a little further.  One thing that seems quite feasible is to embed the JSON for the MapFish requests in a PostgreSQL table.  Why there and not just within our client?  Well, we can use PostGIS to construct really clever multi-page prints if we want to, build into PostGIS the logic to decide the orientation, number of pages, scale, and other information needed to decide how best to print this object, and we can access that JSON through a GetFeatureInfo Request through any WMS compliant server (e.g. GeoServer).  In this way, we can use the GetFeatureInfo bubble as a place where we have links (enhanced with a little javascript) to post the JSON to our MapFish service and return a PDF.

Any object we want exposed through our interface could have a link associated with it that generates a pdf map of that object.  Let’s start with the functionality we want in our PostgreSQL function and figure out what it needs to generate the JSON we want. Here’s what we want our JSON to look like, at least for a very simple example:

{
	"units" : "ft",
	"srs" : "EPSG:3734",
	"layout" : "1) LETTER 8.5x11 Portrait",
	"dpi" : 300,
	"serviceParams" : {
		"locale" : "en_US"
	},
	"resourcesUrl" : "http://maps/geoserver/www/printing",
	"layersMerging" : true,
	"preferredIntervalFractions" : [0.1, 0.2, 0.4],
	"metaTitle" : "Title Here Please! GIS Print",
	"metaAuthor" : "Title Here Please!",
	"metaSubject" : "Title Here Please! GIS Print",
	"metaKeywords" : "",
	"outputFilename" : "cm_gis",
	"legends" : [],
	"layers" : [{
			"baseURL" : "http://maps/geoserver/wms?",
			"opacity" : 1,
			"singleTile" : false,
			"type" : "WMS",
			"layers" : ["cuy_bridge_decks", "planet_osm_line_outside_cuy_map", "cuy_roads_poly", "cuy_street_centerlines", "reservation_bounds_solid"],
			"format" : "image/png",
			"styles" : [""],
			"customParams" : {
				"TILED" : "false",
				"TRANSPARENT" : true
			}
		}
	],
	"pages" : [{
			"center" : [2160649.7795275, 597547.8687664],
			"scale" : 6000,
			"rotation" : 0,
			"mapTitle" : "Title Here Please!"
		}
	]
}

As a starting point, we can split this into two sections, the global parameters, i.e. everything except “pages” (pages is what we want postgis to calculate for us).  In the most generic sense, we would want to pass all of the parameters in the global section to the function, plus the geometry of the object over which we want to print the extent, plus the actual print size of the printable area for the desired layout have it return the json, with a population of pages section done by a little PostGIS magic. PL/pgSQL to come… .

Posted in Database, GeoExt, GeoExt, GeoServer, MapFish, PostGIS, PostgreSQL, SQL | Tagged: , , , , , , , , | Leave a Comment »

Mapfish Play cont. Musings on PostGIS driven Mapfish requests– Code only

Posted by smathermather on March 8, 2012

Code only post-- which only means it's been out here not-quite ready to post for a month.  Now I post out of shear annoyance with myself... .
SELECT '{"units":"ft","srs":"EPSG:3734","layout":"1) LETTER 8.5x11 Portrait","dpi":300,"serviceParams":{"locale":"en_US"},"resourcesUrl":"http://maps/geoserver/www/printing","layersMerging":true,"preferredIntervalFractions":[0.1,0.2,0.4],"metaTitle":"GIS Print","metaAuthor":"","metaSubject":"GIS Print","metaKeywords":"","outputFilename":"cm_gis","legends":[{"name":"","classes":[{"name":"Reservation","icons":["http://maps/geoserver/wms?&VERSION=1.1.0&REQUEST=GetLegendGraphic&LAYER=reservation_bounds&HEIGHT=10&WIDTH=10&FORMAT=image%2Fpng&TRANSPARENT=true&LEGEND_OPTIONS=forceLabels%3Afalse&EXCEPTIONS=application%2Fvnd.ogc.se_xml&RULE=unrestricted"]},{"name":"Restricted","icons":["http://maps/geoserver/wms?&VERSION=1.1.0&REQUEST=GetLegendGraphic&LAYER=reservation_bounds&HEIGHT=10&WIDTH=10&FORMAT=image%2Fpng&TRANSPARENT=true&LEGEND_OPTIONS=forceLabels%3Afalse&EXCEPTIONS=application%2Fvnd.ogc.se_xml&RULE=restricted"]}]},{"name":"Detailed Hydro","classes":[{"name":"Ditch","icons":["http://maps/geoserver/wms?&VERSION=1.1.0&REQUEST=GetLegendGraphic&LAYER=detailed_hydro_view&HEIGHT=10&WIDTH=10&FORMAT=image%2Fpng&TRANSPARENT=true&LEGEND_OPTIONS=forceLabels%3Afalse&EXCEPTIONS=application%2Fvnd.ogc.se_xml&RULE=cm_streams_ditch"]},{"name":"Non-Stream Waterway","icons":["http://maps/geoserver/wms?&VERSION=1.1.0&REQUEST=GetLegendGraphic&LAYER=detailed_hydro_view&HEIGHT=10&WIDTH=10&FORMAT=image%2Fpng&TRANSPARENT=true&LEGEND_OPTIONS=forceLabels%3Afalse&EXCEPTIONS=application%2Fvnd.ogc.se_xml&RULE=cm_streams_ditch"]},{"name":"Stream","icons":["http://maps/geoserver/wms?&VERSION=1.1.0&REQUEST=GetLegendGraphic&LAYER=detailed_hydro_view&HEIGHT=10&WIDTH=10&FORMAT=image%2Fpng&TRANSPARENT=true&LEGEND_OPTIONS=forceLabels%3Afalse&EXCEPTIONS=application%2Fvnd.ogc.se_xml&RULE=cm_streams_stream"]},{"name":"Stream or River","icons":["http://maps/geoserver/wms?&VERSION=1.1.0&REQUEST=GetLegendGraphic&LAYER=detailed_hydro_view&HEIGHT=10&WIDTH=10&FORMAT=image%2Fpng&TRANSPARENT=true&LEGEND_OPTIONS=forceLabels%3Afalse&EXCEPTIONS=application%2Fvnd.ogc.se_xml&RULE=Stream%20or%20River"]},{"name":"Pond","icons":["http://maps/geoserver/wms?&VERSION=1.1.0&REQUEST=GetLegendGraphic&LAYER=detailed_hydro_view&HEIGHT=10&WIDTH=10&FORMAT=image%2Fpng&TRANSPARENT=true&LEGEND_OPTIONS=forceLabels%3Afalse&EXCEPTIONS=application%2Fvnd.ogc.se_xml&RULE=Pond"]},{"name":"Lake Erie","icons":["http://maps/geoserver/wms?&VERSION=1.1.0&REQUEST=GetLegendGraphic&LAYER=detailed_hydro_view&HEIGHT=10&WIDTH=10&FORMAT=image%2Fpng&TRANSPARENT=true&LEGEND_OPTIONS=forceLabels%3Afalse&EXCEPTIONS=application%2Fvnd.ogc.se_xml&RULE=Lake"]},{"name":"Other Wet Areas","icons":["http://maps/geoserver/wms?&VERSION=1.1.0&REQUEST=GetLegendGraphic&LAYER=detailed_hydro_view&HEIGHT=10&WIDTH=10&FORMAT=image%2Fpng&TRANSPARENT=true&LEGEND_OPTIONS=forceLabels%3Afalse&EXCEPTIONS=application%2Fvnd.ogc.se_xml&RULE=Other%20Wet%20Areas"]}]},{"name":"Trails","classes":[{"name":"ADA, APT","icons":["http://maps/geoserver/wms?&VERSION=1.1.0&REQUEST=GetLegendGraphic&LAYER=cm_trails&HEIGHT=10&WIDTH=10&FORMAT=image%2Fpng&TRANSPARENT=true&LEGEND_OPTIONS=forceLabels%3Afalse&EXCEPTIONS=application%2Fvnd.ogc.se_xml&RULE=rule01"]},{"name":"Bridle","icons":["http://maps/geoserver/wms?&VERSION=1.1.0&REQUEST=GetLegendGraphic&LAYER=cm_trails&HEIGHT=10&WIDTH=10&FORMAT=image%2Fpng&TRANSPARENT=true&LEGEND_OPTIONS=forceLabels%3Afalse&EXCEPTIONS=application%2Fvnd.ogc.se_xml&RULE=rule02"]},{"name":"Hiking","icons":["http://maps/geoserver/wms?&VERSION=1.1.0&REQUEST=GetLegendGraphic&LAYER=cm_trails&HEIGHT=10&WIDTH=10&FORMAT=image%2Fpng&TRANSPARENT=true&LEGEND_OPTIONS=forceLabels%3Afalse&EXCEPTIONS=application%2Fvnd.ogc.se_xml&RULE=rule03"]},{"name":"Mountain Bike Trails","icons":["http://maps/geoserver/wms?&VERSION=1.1.0&REQUEST=GetLegendGraphic&LAYER=cm_trails&HEIGHT=10&WIDTH=10&FORMAT=image%2Fpng&TRANSPARENT=true&LEGEND_OPTIONS=forceLabels%3Afalse&EXCEPTIONS=application%2Fvnd.ogc.se_xml&RULE=rule04"]},{"name":"Connector Trail","icons":["http://maps/geoserver/wms?&VERSION=1.1.0&REQUEST=GetLegendGraphic&LAYER=cm_trails&HEIGHT=10&WIDTH=10&FORMAT=image%2Fpng&TRANSPARENT=true&LEGEND_OPTIONS=forceLabels%3Afalse&EXCEPTIONS=application%2Fvnd.ogc.se_xml&RULE=rule05"]}]}],"layers":[{"baseURL":"http://maps/geoserver/wms?","opacity":1,"singleTile":false,"type":"WMS","layers":["cuy_bridge_decks","planet_osm_line_outside_cuy_map","cuy_roads_poly","cuyahoga_street_centerlines","reservation_bounds_solid"],"format":"image/png","styles":[""],"customParams":{"TILED":"false","TRANSPARENT":true}},{"baseURL":"http://maps/geoserver/wms?","opacity":1,"singleTile":false,"type":"WMS","layers":["reservation_bounds"],"format":"image/png","styles":[""],"customParams":{"TRANSPARENT":true,"TILED":false}},{"baseURL":"http://maps/geoserver/wms?","opacity":1,"singleTile":false,"type":"WMS","layers":["detailed_hydro_view"],"format":"image/png","styles":[""],"customParams":{"TRANSPARENT":true,"TILED":false}},{"baseURL":"http://maps/geoserver/wms?","opacity":1,"singleTile":false,"type":"WMS","layers":["cm_bridge_view"],"format":"image/png","styles":[""],"customParams":{"TRANSPARENT":true,"TILED":false}},{"baseURL":"http://maps/geoserver/wms?","opacity":1,"singleTile":false,"type":"WMS","layers":["cm_trails"],"format":"image/png","styles":[""],"customParams":{"TRANSPARENT":true,"TILED":false}},{"baseURL":"http://maps/geoserver/wms?","opacity":1,"singleTile":false,"type":"WMS","layers":["impervious_update","cm_buildings","cm_buildings_outline"],"format":"image/png","styles":[""],"customParams":{"TILED":"false","TRANSPARENT":true}},{"baseURL":"http://maps/geoserver/wms?","opacity":1,"singleTile":false,"type":"WMS","layers":["golf_view"],"format":"image/png","styles":[""],"customParams":{"TILED":"false","TRANSPARENT":true}},{"baseURL":"http://maps/geoserver/wms?","opacity":1,"singleTile":false,"type":"WMS","layers":["nhd_lake_erie"],"format":"image/png","styles":[""],"customParams":{"TILED":"false","TRANSPARENT":true}},{"baseURL":"http://maps/geoserver/wms?","opacity":1,"singleTile":false,"type":"WMS","layers":["reservation_boundaries_public_private_cm_dissolved_mask_gradien"],"format":"image/png","styles":[""],"customParams":{"TILED":"false","TRANSPARENT":true}},{"baseURL":"http://maps/geoserver/wms?","opacity":1,"singleTile":true,"type":"WMS","layers":["supplementary_shields","odot_interstate","odot_us_routes","odot_state_routes","planet_osm_line","cuyahoga_street_centerlines_labels","planet_osm_line_outside_cuy","detailed_hydro_labels","facilities_cm","facility_areas_cm"],"format":"image/png","styles":[""],"customParams":{"TILED":"false","TRANSPARENT":true}}],"pages":[{"center":[' || ST_X(ST_Centroid(the_geom)) || ',' || ST_Y(ST_Centroid(the_geom)) || '],"scale":2400,"rotation":0,"mapTitle":""}]}'::text
FROM loops
WHERE (ST_XMax(ST_Envelope(the_geom)) - ST_XMin(ST_Envelope(the_geom))) < (ST_YMax(ST_Envelope(the_geom)) - ST_YMin(ST_Envelope(the_geom)))
AND
(ST_YMax(ST_Envelope(the_geom)) - ST_YMin(ST_Envelope(the_geom))) < 7900
SELECT 'landscape, linear follow'::text, ST_Centroid(the_geom)
	FROM loops
		WHERE (ST_XMax(ST_Envelope(the_geom)) - ST_XMin(ST_Envelope(the_geom))) > (ST_YMax(ST_Envelope(the_geom)) - ST_YMin(ST_Envelope(the_geom)))
			AND
		(ST_XMax(ST_Envelope(the_geom)) - ST_XMin(ST_Envelope(the_geom))) > 15800

UNION ALL

SELECT 'landscape, quad page'::text, ST_Centroid(the_geom)
	FROM loops
		WHERE (ST_XMax(ST_Envelope(the_geom)) - ST_XMin(ST_Envelope(the_geom))) > (ST_YMax(ST_Envelope(the_geom)) - ST_YMin(ST_Envelope(the_geom)))
			AND
		(ST_XMax(ST_Envelope(the_geom)) - ST_XMin(ST_Envelope(the_geom))) > 7900
			AND
		(ST_XMax(ST_Envelope(the_geom)) - ST_XMin(ST_Envelope(the_geom))) <= 15800

UNION ALL

SELECT 'landscape, single page'::text, ST_Centroid(the_geom)
	FROM loops
		WHERE (ST_XMax(ST_Envelope(the_geom)) - ST_XMin(ST_Envelope(the_geom))) > (ST_YMax(ST_Envelope(the_geom)) - ST_YMin(ST_Envelope(the_geom)))
			AND
		(ST_XMax(ST_Envelope(the_geom)) - ST_XMin(ST_Envelope(the_geom))) < 7900

UNION ALL

SELECT 'portrait, quad page'::text, ST_Centroid(the_geom)
	FROM loops
		WHERE (ST_XMax(ST_Envelope(the_geom)) - ST_XMin(ST_Envelope(the_geom))) < (ST_YMax(ST_Envelope(the_geom)) - ST_YMin(ST_Envelope(the_geom)))
			AND
		(ST_YMax(ST_Envelope(the_geom)) - ST_YMin(ST_Envelope(the_geom))) > 7900
			AND
		(ST_YMax(ST_Envelope(the_geom)) - ST_YMin(ST_Envelope(the_geom))) <= 15800

UNION ALL

SELECT 'portrait, single page'::text, ST_Centroid(the_geom)
	FROM loops
		WHERE (ST_XMax(ST_Envelope(the_geom)) - ST_XMin(ST_Envelope(the_geom))) < (ST_YMax(ST_Envelope(the_geom)) - ST_YMin(ST_Envelope(the_geom)))
			AND
		(ST_YMax(ST_Envelope(the_geom)) - ST_YMin(ST_Envelope(the_geom))) < 7900

UNION ALL

SELECT 'portrait, linear follow'::text, ST_Centroid(the_geom)
	FROM loops
		WHERE (ST_XMax(ST_Envelope(the_geom)) - ST_XMin(ST_Envelope(the_geom))) < (ST_YMax(ST_Envelope(the_geom)) - ST_YMin(ST_Envelope(the_geom)))
			AND
		(ST_YMax(ST_Envelope(the_geom)) - ST_YMin(ST_Envelope(the_geom))) > 15800
;

Posted in Database, GeoServer, MapFish, Other, PostGIS, PostgreSQL, Recreation, SQL, Trail Curation, Trails | Tagged: , , , , , , | 1 Comment »

#OGC Web Services and #Security

Posted by smathermather on March 6, 2012

A while back, I had a (somewhat cryptic) post on OGC services and security.  A couple months later, I saw this post on GeoSolution’s site on GeoServer security and the ins and outs of various options, from native to proxied security.  It is quite a bit more nuanced than my own… .  I recommend you read it, even if you don’t use GeoServer– it is enlightening about the specific problems of securing spatial data that go beyond the simple authentication/authorization models that apply to most other datasets.

Posted in GeoServer, Other, Security | Tagged: , , | Leave a Comment »

Building simple clients for MapFish — Underlying Infrastructure

Posted by smathermather on February 10, 2012

In order to build simple clients for the MapFish print service, we have to understand what the protocols are that are invoked and how they function.  To do this we can read the MapFish Print Module Doc, and then modify and vamp from there.  While I was going to joke that this would be an excellent cure for insomnia, the joke fell apart when I actually read the Print Module Doc, and it was clear, concise, readable, and frankly at least as interesting as most of my blog entries (no comments here please).

But, I did that after the fact.  In other words, I did it the hard way– just like you do when you bring home that really cool electronic toy, and play with it for a couple hours before (maybe, if ever) picking up the manual.  So for me, instead of reading the excellent documentation, I sniffed the protocol using a GeoExt interface to a GeoServer/MapFish combo with Firebug.  (quick aside– if you write web stuff and are new to it, then you should know you should use Firebug to write it better and test it on the fly– or if you’re a cool kid with horn-rimmed glasses and an ironic t-shirt, do it in Google Chrome’s Javascript Console, it makes no real difference as far as outcomes, just a difference in style).

In sniffing the protocol, I saw that my request for a PDF was a POST request to the server, with a JSON object as the request.  In short, the interface converts my form information into a bunch of text (a javascript object) which it pushes to the server.  The server location in this case is: http://localhost:8080/geoserver/pdf/create.json.  The text it’s pushing is a file which reads something like this:

{
	"units" : "ft",
	"srs" : "EPSG:3734",
	"layout" : "1) LETTER 8.5x11 Portrait",
	"dpi" : 300,
	"serviceParams" : {
		"locale" : "en_US"
	},
	"resourcesUrl" : "http://maps/geoserver/www/printing",
	"layersMerging" : true,
	"preferredIntervalFractions" : [0.1, 0.2, 0.4],
	"metaTitle" : "Title Here Please! GIS Print",
	"metaAuthor" : "Title Here Please!",
	"metaSubject" : "Title Here Please! GIS Print",
	"metaKeywords" : "",
	"outputFilename" : "cm_gis",
	"legends" : [],
	"layers" : [{
			"baseURL" : "http://maps/geoserver/wms?",
			"opacity" : 1,
			"singleTile" : false,
			"type" : "WMS",
			"layers" : ["cuy_bridge_decks", "planet_osm_line_outside_cuy_map", "cuy_roads_poly", "cuyahoga_street_centerlines", "reservation_bounds_solid"],
			"format" : "image/png",
			"styles" : [""],
			"customParams" : {
				"TILED" : "false",
				"TRANSPARENT" : true
			}
		}
	],
	"pages" : [{
			"center" : [2160649.7795275, 597547.8687664],
			"scale" : 6000,
			"rotation" : 0,
			"mapTitle" : "Title Here Please!"
		}
	]
}

I’ll call your attention to the last little bit of code in the object:


"pages" : [{
		"center" : [2160649.7795275, 597547.8687664],
		"scale" : 6000,
		"rotation" : 0,
		"mapTitle" : "Title Here Please!"
	}

]

I was proud of myself for recognizing (through the haze of a guy who’s modified a lot of javascript, but never learned it proper-like) that this is a javascript array with just one object.  Which means, we can make it an array with more than one object.  Eureka!  multi-page pdfs with just 5-6 more lines of code:


"pages" : [{
		"center" : [2160649.7795275, 597547.8687664],
		"scale" : 6000,
		"rotation" : 0,
		"mapTitle" : "Title Here Please!"
	}, {
		"center" : [2216902.0734907, 596701.84251968],
		"scale" : 1800,
		"rotation" : 0,
		"mapTitle" : "Title Here Please!"
	}
]

Now, just to figure out how to test this out without building a web page to do it.  curl is our friend here, just a few extra flags for telling the server what we are doing with the json file (thanks to this post):

curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X POST -d @test.json http://localhost:8080/geoserver/pdf/create.json

And now for all the json fit to print:

{
	"units" : "ft",
	"srs" : "EPSG:3734",
	"layout" : "1) LETTER 8.5x11 Portrait",
	"dpi" : 300,
	"serviceParams" : {
		"locale" : "en_US"
	},
	"resourcesUrl" : "http://maps/geoserver/www/printing",
	"layersMerging" : true,
	"preferredIntervalFractions" : [0.1, 0.2, 0.4],
	"metaTitle" : "Title Here Please! GIS Print",
	"metaAuthor" : "Title Here Please!",
	"metaSubject" : "Title Here Please! GIS Print",
	"metaKeywords" : "",
	"outputFilename" : "cm_gis",
	"legends" : [],
	"layers" : [{
			"baseURL" : "http://maps/geoserver/wms?",
			"opacity" : 1,
			"singleTile" : false,
			"type" : "WMS",
			"layers" : ["cuy_bridge_decks", "planet_osm_line_outside_cuy_map", "cuy_roads_poly", "cuyahoga_street_centerlines", "reservation_bounds_solid"],
			"format" : "image/png",
			"styles" : [""],
			"customParams" : {
				"TILED" : "false",
				"TRANSPARENT" : true
			}
		}
	],
	"pages" : [{
			"center" : [2160649.7795275, 597547.8687664],
			"scale" : 6000,
			"rotation" : 0,
			"mapTitle" : "Title Here Please!"
		}, {
			"center" : [2216902.0734907, 596701.84251968],
			"scale" : 1800,
			"rotation" : 0,
			"mapTitle" : "Title Here Please!"
		}
	]
}

*Updated with better formatted sourcecode, thanks to notepad++’s JSMin plugin

Posted in Database, GeoExt, GeoExt, GeoServer, MapFish, PostGIS, PostgreSQL, SQL | Tagged: , , , , , , , , | 1 Comment »