Search code examples
javageotools

Retrieve map data via WFS with GeoTools


I'm trying to retrieve data from a LuciadFusion wfs server using GeoTools, but is having troubles finding examples on how to achieve my goals.

The idea is that I'm tracking moving stuff, and want to retrieve map data (features) from the areas my moving tings is moving into, and then calculate distances (like how far to nearest road, nearest lake coastal shore).

I want to get the features, put them into a SpatialIndexFeatureCollection (kept in memory for quick access, as I'm tracking multiple moving objects), where I can query the stuff I want to know.

So far I'm querying some random wfs server I found with data: http://ogc.bgs.ac.uk/digmap625k_gsml32_insp_gs/wfs?. I'm able to read the capabilities, and from one of the typenames building my SpatialIndexFeatureCollection:

String url =  "http://ogc.bgs.ac.uk/digmap625k_gsml32_insp_gs/wfs?";

Map connectionParameters = new HashMap();
connectionParameters.put("WFSDataStoreFactory:GET_CAPABILITIES_URL", url)
connectionParameters.put(WFSDataStoreFactory.TIMEOUT.key, 100000);
WFSDataStoreFactory  dsf = new WFSDataStoreFactory();

try {
   WFSDataStore dataStore = dsf.createDataStore(connectionParameters);

   for(String s : dataStore.getTypeNames()){
      System.out.println(s);

   }

   SimpleFeatureSource source = dataStore.getFeatureSource("test:uk_625k_mapped_feature");
   SimpleFeatureCollection fc = source.getFeatures();
   System.out.println(fc.getBounds());

   SpatialIndexFeatureCollection index = new SpatialIndexFeatureCollection();
   fc.accepts(new FeatureVisitor() {
      @Override
      public void visit(Feature feature) {
         SimpleFeature simpleFeature = (SimpleFeature) feature;
         Geometry geom = (MultiPolygon) simpleFeature.getDefaultGeometry();

         if(geom != null) {
            Envelope env = geom.getEnvelopeInternal();

            if(!env.isNull()) {
               index.add(simpleFeature);
            }
         }
      }
   }, new NullProgressListener());

catch (FactoryException e) {
   aLog.error("", e);
}

Running it prints:

  • gsml:MappedFeature
  • gsmlgu:GeologicUnit
  • test:uk_625k_mapped_feature
  • ReferencedEnvelope[-132576.7891571155 : 743466.624998733, -15669.960592884949 : 1248847.1762802668]

However, when my own WFS server has been setup, it will contain many more typenames each describing fx roads or lakes for an area. And for many areas.

How do I get the typenames relevant for a defined area (a boundingbox BB), or maybe even only the features in a typename covered by the BB if it's possible?

Second, when extracting data from the example above, all the features is in a wrong CoordinateReferenceSystem - how do I force it to be EPSG:4326?

Thanks!


Solution

  • First to clarify terminology:

    1. a TypeName is an identifier of a type of data or a schema.
    2. a Feature is the actual piece of data that has position and attributes.

    To restrict the number of features returned you need to make use of a Query object. This allows you to specify a Filter to restrict the features returned. In the case of a WFSDatastore (and most others) it is converted into something the underlying store understands and handled there. You can create features in all sorts of ways including a FilterFactory but the easiest is to use ECQL which allows you to write more human understandable filters directly. There is a helpful tutorial here.

        Filter filter = ECQL.toFilter("BBOX(the_geom, 500000, 700000, 501000, 701000)");
        query.setFilter(filter);
        query.setMaxFeatures(10);
        SimpleFeatureCollection fc = source.getFeatures(query);
    

    As for reprojection WFS doesn't handle that directly but you could use a ReprojectingFeatureCollection to wrap your results.

    ReprojectingFeatureCollection rfc = new ReprojectingFeatureCollection(fc, DefaultGeographicCRS.WGS84);
    

    Unless you are expecting a lot of invalid polygons then you should be able to build a spatial indexed collection using:

    SpatialIndexFeatureCollection index = new SpatialIndexFeatureCollection(fc.getSchema());
    index.addAll(fc);