Should we make a tutorial based on this material ?.
Geoserver or Geotools documentation ?. I would prefer sphinx, so Geoserver is my favorite. ---------------------------------------------------------------- This message was sent using IMP, the Internet Messaging Program.
Geoserver Feature-Pregeneralized with PostGIS datastore
Introduction
This tutorial is meant as an introduction to using the Feature-Pregeneralized Geoserver plugin with a PostGIS database. It is based on the general Feature-Pregeneralized tutorial and the GeoTools Feature-pregeneralized documentation. This tutorial uses as an example how to use the norwegian N50 (data optimized for 1:50000 scale) map data to create a map of Norway, but can be applied to other datasets as well.
Motivation
The original data is quite detailed, and thus leads to long rendering times for zoom-levels covering the whole of Norway. The first step is thus to figure out which layers are used at these zoom-levels, and how much they can be generalized. In this case theree layers where identified as used at these zoom-levels. These where:
- adminomrader_pol: administrative areas, used as backdrop
- arealdekke_pol: area usage, used for the sea surface and vegetation
- samferdsel_lin: roads and railroads
Each of these layers was already imported into PostGIS as tables (from shapefiles) and published as layers in Geoserver, and a solution that neither included reimporting the data, nor caused any redundant data to be stored was wanted. This rules out using the approach of generalizing the original shapefiles before the import and using one table pr generalization (what is referred to as "Vertical layout").
The GeoTools docs also mentiones a "Horiontal layout", illustrated as
| FID | CAT_ID | CAT_DESCR | the_geom | the_geom_5 | the_geom_10 | the_geom_20 | the_geom50 |
|---|---|---|---|---|---|---|---|
| streams.1 | 1 | 4711 | g1(1) | g1(5) | g1(10) | g1(20) | g1(50) |
| streams.2 | 2 | 4712 | g2(1) | g2(5) | g2(10) | g2(20) | g2(50) |
This layout solves the problem of redundancy, and it eliminates the need for reimporting the data. Thus, this tutorial covers how to setup such a horizontal layout using PostGIS.
Database modifications
Assuming that the original data is imported to PostGIS, each having the geometry in the "the_geom" column, and the wish to add features generalized to 50m, 250m and 500m, the task of modifying the tables is quite simple, and consists of three steps:
- Extend the tables with new geometry columns
- Generate the generalized geometries
- Create spatial indicies for the new geometries
The PostGIS AddGeometryColumn is used to add new columns, for the adminomrader_pol table, this is done in this manner:
SELECT AddGeometryColumn('','adminomrader_pol','the_geom50','32633','MULTIPOLYGON',2);
SELECT AddGeometryColumn('','adminomrader_pol','the_geom250','32633','MULTIPOLYGON',2);
SELECT AddGeometryColumn('','adminomrader_pol','the_geom500','32633','MULTIPOLYGON',2);
Take care to use the same geometry-type as the original "the_geom"
The second step is t0 populate the generalzed geometry columns. This can be done using the PostGIS function ST_SimplifyPreserveTopology, which preservers topology. The tolerance is set to the wanted generalization. In this example the SQL is:
UPDATE adminomrader_pol SET the_geom50 = multi(ST_SimplifyPreserveTopology(the_geom,50));
UPDATE adminomrader_pol SET the_geom250 = multi(ST_SimplifyPreserveTopology(the_geom,250));
UPDATE adminomrader_pol SET the_geom500 = multi(ST_SimplifyPreserveTopology(the_geom,500));
NOTE: ST_SimplifyPreserveTopology returns simple geometries, so to continue using MULT-geometries the multi()-function must be used. Another solution is of course to use simple geometries. This operation can take a considerable amount of time.
The spatial indicies are straightforward:
CREATE INDEX polygon_index_adminomrader_pol_50 ON adminomrader_pol USING GIST (the_geom50);
CREATE INDEX polygon_index_adminomrader_pol_250 ON adminomrader_pol USING GIST (the_geom250);
CREATE INDEX polygon_index_adminomrader_pol_500 ON adminomrader_pol USING GIST (the_geom500);
VACUUM ANALYZE adminomrader_pol;
This concludes the database work needed. To check the result, a query like "SELECT npoints(the_geom) as the_geom, npoints(the_geom50) as the_geom50, npoints(the_geom250) as the_geom250, npoints(the_geom500) as the_geom500 from adminomrader_pol LIMIT 10;" can be executed. In this case the result is:
the_geom | the_geom50 | the_geom250 | the_geom500
----------+------------+-------------+-------------
3166 | 100 | 45 | 35
1844 | 119 | 45 | 24
6941 | 198 | 59 | 33
4126 | 127 | 54 | 35
607 | 91 | 43 | 31
7779 | 166 | 50 | 27
98 | 27 | 27 | 19
607 | 65 | 28 | 22
5655 | 148 | 45 | 31
12576 | 247 | 74 | 45
Geoserver setup
First install the plugin (ie. drop the .jar files in the lib catalog of Geoserver and restart). Then ensure that Geoserver detects the new columns on the existing layers (edit layer, check under "Feature Type Details", the_geom50, the_geom250 and the_geom500 should be listed). If not, try "Reload feature type", then they should appear.
The next step is to create an xml-file describing the generalized datastore, for this example it looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<GeneralizationInfos version="1.0">
<GeneralizationInfo dataSourceNameSpace="n50" dataSourceName="postgis_n50" featureName="adminomrader_pol" baseFeatureName="adminomrader_pol" geomPropertyName="the_geom">
<Generalization dataSourceNameSpace="n50" dataSourceName="postgis_n50" distance="50" featureName="adminomrader_pol" geomPropertyName="the_geom50"/>
<Generalization dataSourceNameSpace="n50" dataSourceName="postgis_n50" distance="250" featureName="adminomrader_pol" geomPropertyName="the_geom250"/>
<Generalization dataSourceNameSpace="n50" dataSourceName="postgis_n50" distance="500" featureName="adminomrader_pol" geomPropertyName="the_geom500"/>
</GeneralizationInfo>
<GeneralizationInfo dataSourceNameSpace="n50" dataSourceName="postgis_n50" featureName="samferdsel_lin" baseFeatureName="samferdsel_lin" geomPropertyName="the_geom">
<Generalization dataSourceNameSpace="n50" dataSourceName="postgis_n50" distance="50" featureName="samferdsel_lin" geomPropertyName="the_geom50"/>
<Generalization dataSourceNameSpace="n50" dataSourceName="postgis_n50" distance="250" featureName="samferdsel_lin" geomPropertyName="the_geom250"/>
<Generalization dataSourceNameSpace="n50" dataSourceName="postgis_n50" distance="500" featureName="samferdsel_lin" geomPropertyName="the_geom500"/>
</GeneralizationInfo>
<GeneralizationInfo dataSourceNameSpace="n50" dataSourceName="postgis_n50" featureName="arealdekke_pol" baseFeatureName="arealdekke_pol" geomPropertyName="the_geom">
<Generalization dataSourceNameSpace="n50" dataSourceName="postgis_n50" distance="50" featureName="arealdekke_pol" geomPropertyName="the_geom50"/>
<Generalization dataSourceNameSpace="n50" dataSourceName="postgis_n50" distance="250" featureName="arealdekke_pol" geomPropertyName="the_geom250"/>
<Generalization dataSourceNameSpace="n50" dataSourceName="postgis_n50" distance="500" featureName="arealdekke_pol" geomPropertyName="the_geom500"/>
</GeneralizationInfo>
</GeneralizationInfos>
Note that baseFeatureName refers to the existing layer in Geoserver. The fact that the featureName is identical is a pure coincidence, and perhaps not the best solution, as it may cause confusion.
This xml file should be placed in a directory Geoserver can read from, $GEOSERVER_DATA_DIR/data is a good choice. The next step is to add a new datastore. Choose "Stores" and "Add new Store" in Geoserver. " Generalizing data store - Data store supporting generalized geometries" should be listed. Give the store a name, assign a workspace and enter the path to the xml file in "GeneralizationInfosProviderParam" (typically: file:data/myfile.xml). Also remember to change org.geotools.* to org.geoserver.* in the fields "RepositoryClassName" and "GeneralizationInfosProviderClassName".
Saving this store should enable you to publish layers as usual. To see that generalized features is in fact used, preview a pre-generalized layer and look for something like:
Jun 10, 2010 9:03:35 AM org.geotools.data.gen.PreGeneralizedFeatureSource logDistanceInfo
INFO: Using generalizsation: postgis_n50 arealdekke_pol the_geom500 500.0
in the logs.
Conclusion
By now you should know how to set up pregeneralized features using PostGIS. You might have to fine-tune (by guesswork or maths) to find the generalizing distances that works for your data. Thanks to Christian Mueller for help with bugfixes and guidance.
------------------------------------------------------------------------------ ThinkGeek and WIRED's GeekDad team up for the Ultimate GeekDad Father's Day Giveaway. ONE MASSIVE PRIZE to the lucky parental unit. See the prize list and enter to win: http://p.sf.net/sfu/thinkgeek-promo
_______________________________________________ Geotools-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/geotools-devel
