1

I need to iterate through an already sorted SimpleFeatureCollection by theirs geometrie's area.

I figured out that the classic SimpleFeatureIterator comes unsorted and a SortedFeatureIterator( SimpleFeatureIterator iterator, SimpleFeatureType schema,SortBy[] sortBy, int maxFeatures) object exists, which I tried to use.

This sortBy object needs a PropertyName, which must be generated by a FilterFactory I guess. Here is my problem : I cannot find how to set this property to run with a function. I found that org.opengis.filter.expression.Function exists, such as org.opengis.filter.expression.Function.AreaFunction would be appropriate. But as PropertyName and AreaFunction both extends the org.opengis.filter.expression.Expression interface, I cannot find a way to put the function into the SortBy object. I tried couple of things and looked, but found no solution.

Any idea? Am I having the right way of thinking and did I miss a salvation methods? Thanks a lot for your help.

PS: Area is not an attribute of my collection (though about that for a dirty hack solution, but I try to avoid them...)

Code example:

       SimpleFeatureIterator sfcIt = sfc.features();   
       FilterFactory2 ff = FeatureUtilities.DEFAULT_FILTER_FACTORY;
       Function function = new AreaFunction();
           //first intention
       SortBy[] s = {ff.sort(function.toString(), SortOrder.ASCENDING)};
       //second intention
       Expression expr = ff.function(function.toString(), ff.property("the_geom"));
       //desperate intention
       final PropertyName propertyName = (PropertyName) function; //utopic
       final PropertyName propertyName = ff.arithmeticOperators(true, function); //that isn't the same function object... 

       SortBy[] sort = { new SortByImpl(expr, SortOrder.ASCENDING) };      
       SortBy[] sort = { new SortByImpl(propertyName, SortOrder.ASCENDING) };      

       SortedFeatureIterator sfcIter = new SortedFeatureIterator(sfcIter, sfc.getSchema(), sort, sfc.size());



Thanks for your opinion ! Maxime Colomb

1 Answers1

0

Unfortunately, SortBy is defined to only take a property name so there is no way to add a function in there. This is because the SortBy object comes from the WFS standard and there it is restricted to be a property name. There is no reason why you couldn't extend the code to handle expressions there (we've extended plenty of other parts of the OGC specifications to suite our needs.

But for a quick sort by area with out explicitly adding an area attribute to your features you could do something like:

    Unit<Area> sq_mile = USCustomary.MILE.multiply(USCustomary.MILE).asType(Area.class);
    File file = new File("../../data/states.shp");
    FileDataStore store = FileDataStoreFinder.getDataStore(file);
    SimpleFeatureSource featureSource = store.getFeatureSource();
    SortedMap<Quantity<Area>, SimpleFeature> index = new TreeMap<>();
    try(SimpleFeatureIterator itr = featureSource.getFeatures().features()){
      while (itr.hasNext()) {
        SimpleFeature feature = itr.next();
        Quantity<Area> area = calcArea(feature);
        index.put(area, feature);
      }
    }

    for (Entry<Quantity<Area>, SimpleFeature> entry : index.entrySet()) {
      Quantity<Area> quantity = entry.getKey().to(sq_mile);
      String out = String.format("%-30s % 8.0f %s", entry.getValue().getAttribute("STATE_NAME"), quantity.getValue(),
          quantity.getUnit());
      System.out.println(out);
    }

Which gives:

District of Columbia                 66 mi²
Rhode Island                       1045 mi²
Delaware                           2053 mi²
Connecticut                        4977 mi²
New Jersey                         7502 mi²
Massachusetts                      8178 mi²
New Hampshire                      9262 mi²
Vermont                            9604 mi²
Maryland                           9740 mi²
West Virginia                     24214 mi²
South Carolina                    30849 mi²
Maine                             32141 mi²
Indiana                           36378 mi²
Virginia                          39841 mi²
Kentucky                          40333 mi²
Ohio                              41193 mi²
Tennessee                         42098 mi²
Pennsylvania                      45405 mi²
Louisiana                         45824 mi²
Mississippi                       47662 mi²
New York                          48546 mi²
North Carolina                    49073 mi²
Alabama                           51685 mi²
Arkansas                          52889 mi²
Florida                           55839 mi²
Wisconsin                         56136 mi²
Iowa                              56238 mi²
Illinois                          56311 mi²
Michigan                          57901 mi²
Georgia                           58674 mi²
Washington                        67336 mi²
Missouri                          69808 mi²
Oklahoma                          70032 mi²
North Dakota                      70815 mi²
South Dakota                      77208 mi²
Nebraska                          77340 mi²
Kansas                            82205 mi²
Idaho                             83384 mi²
Minnesota                         84498 mi²
Utah                              84840 mi²
Oregon                            97150 mi²
Wyoming                           97891 mi²
Colorado                         104100 mi²
Nevada                           110637 mi²
Arizona                          113695 mi²
New Mexico                       121769 mi²
Montana                          147374 mi²
California                       158017 mi²
Texas                            264714 mi²
Ian Turton
  • 10,018
  • 1
  • 28
  • 47
  • Hi Thanks for your answer ! I would have like to implement that but I don't have the knowledge of types and relationship between every objects. Thanks a lot for your solution though, it's way nicer that what I would have done ! Cheers Max – maxime.colomb Feb 25 '20 at 16:10
  • can you [edit] your question to explain which of the types or relationships you do need – Ian Turton Feb 25 '20 at 16:35
  • Well I was talking about the abstract class ExpressionAbstract, DefaultExpression FunctionExpressionImpl, interface FunctionExpression, and each types of functions (in my example, AreaFunction). For example, if I implement the opportunity to accept functions by SortBy() objects, which state of abstraction should it accept ? Which method would be generic enough to compare the different features ? – maxime.colomb Feb 27 '20 at 10:52
  • You would need to update SortBy to accept an expression rather than just a property name - Sortby handles the comparisons so all you would need would be a function that returned a value. – Ian Turton Feb 27 '20 at 11:31