Tutorial on how to generalize data loaded in CartAGen

The building blocks of map generalization are the algorithms that are triggered on one map object or on group of map objects. Before orchestrating their application on a complete map, it is necessary to learn of to test them on a sample dataset, and that’s the aim of this tutorial. The tutorial:

Where are the algorithms in the Java library?

Generalization operations are atomic transformations of map objects that improve the legibility of the objects at target scale. There are many different taxonomies of generalization operations (or operators), but the one illustrated in the images below derives from Sébastien Mustière’s PhD thesis.

Simplification operations Caricature operations Harmonisation operations

A generalization algorithm is an algorithm that instanciates one or several generalization operations. For instance, the famous Douglas & Peucker algorithm is an algorithm that instanciates the filtering operation.

See more information on generalization operations and algorithms in this chapter from the ICA commission 2014 book.

Most algorithms available in CartAGen are located in the algorithms package of the cartagen-core project. However, some simple geometrical algorithms such as Gaussian smoothing or Douglas & Peucker filtering are included in the geometry computation methods of GeOxygene library, on which CartAGen is built upon.

TIP: To know where the code of an algorithm is, look at the code of the menu button that triggers the algorithm (in the package fr.ign.cogit.cartagen.appli.core.themes of cartagen-appli module).

There is a list of the available algorithms with descriptions at this page

Triggering algorithms with the menu buttons

Generic algorithms

Some of the available algorithms are generic, which means they can be used on different types of geographic features, and even sometimes different types of geometry. For instance, the simplification algorithms provided in CartAGen can be used on any type of line or polygon feature (even if they are not always effective on every type of feature, see the detailed description of the algorithms). Some of these algorithms can be manually triggered on the selected geographic features in the GUI: click on the menu items in the Generalisation->Algorithms menu (see image below).

menu to trigger generic algorithms

Theme specific algorithms

Some other algorithms are clearly dedicated to specific types of features, and cannot be triggered on different features. The ‘Themes’ menu (see image below) contains sub-menus and menu items to use theme-specific algorithms. For instance, the ‘Road Network’ sub-menu contains menu items to ‘Detect Roundabouts’ and ‘Collapse Roundabouts’

theme menus

CartAGen is not supposed to be an interactive platform to carry out generalization on loaded data for production issues. It is intended as a research platform, at least its GUI, and these menus are mostly helpful to design new algorithms and to design new generalization processes that orchestrate different algorithms. For instance, it is useful to test the algorithms on its own data before choosing which ones can be included in an agent-based generalization process.

Example: enlarging and displacing buildings in the sample dataset

What we want to do

What we want to do in this example is to generalize the buildings of the sample dataset to the 1:30,000 scale, by enlarging them, simplifying them and removing symbol overlaps (between two buildings and between buildings and road symbols) by a contextual displacement. The contextual displacement works on a group of buildings to displace them optimally in the free space around them, so first, groups of buildings have to be computed, and each of these groups will be generalize as a whole.

All these steps can be achieved by an interactive use of the GUI menus, but this part of the tutorial shows how to do this by code.

Set the scale and update symbol sizes
	// first, set the symbolisation scale to 1:30k (this is the target scale of the tutorial generalisation process)
	// To do that, we first need to get the current SLD
	StyledLayerDescriptor sld = CartAGenDoc.getInstance().getCurrentDataset().getSld();
	// then update the symbolisation to the new target scale
	SLDUtilCartagen.changeSymbolisationScale(30000.0, sld);
Compute the building groups
      // get the network sections that delimit groups (i.e. roads and rivers)
      IFeatureCollection<IFeature> sections = new FT_FeatureCollection<>();
      sections.addAll(dataset.getRoads());
      sections.addAll(dataset.getWaterLines());

      // create the groups with a 25.0 m threshold for building buffering
      Collection<IUrbanBlock> groups = UrbanEnrichment
          .createBuildingGroups(sections, 25.0, 10.0, 12, 2.0, 5000.0);
Loop on the building groups
	for(IUrbanBlock group: groups){
		// generalise the group...
	}
Enlarge and simplify all the buildings of the group
          // in this case, we only added buildings as urban elements, so no need
          // to check (there can be parks, squares, sports fields...)
          // the class GeneralisationSpecifications is used: it contains
          // standard values for classical generalisation specifications, such
          // as the minimum size of a building in map mm²

          // first enlarge the building geometry
          // compute the goal area
          double area = building.getGeom().area();
          double goalArea = area;
          double aireMini = GeneralisationSpecifications.AIRE_MINIMALE_BATIMENT
              * Legend.getSYMBOLISATI0N_SCALE()
              * Legend.getSYMBOLISATI0N_SCALE() / 1000000.0;
          if (area <= aireMini) {
            goalArea = aireMini;
          }
          // compute the homothety of the building geometry
          IPolygon geom = CommonAlgorithms.homothetie(
              (IPolygon) building.getGeom(), Math.sqrt(goalArea / area));

          // then simplify the building
          IGeometry simplified = SimplificationAlgorithm.simplification(geom,
              GeneralisationSpecifications.LONGUEUR_MINI_GRANULARITE
                  * Legend.getSYMBOLISATI0N_SCALE() / 1000.0);
          
          // apply the new geometry to the building
          building.setGeom(simplified);
Displace the buildings in the group
        // trigger the displacement of the enlarged and simplified features
        BuildingDisplacementRandom.compute(group);

Be careful, the processing time on the whole sample dataset can be long (around 5 minutes).

Guidelines to add a new generalization algorithm into CartAGen

This explains shows the best practices to add a new algorithm in CartAGen. The guidelines are examplified with the addition of the amalgamation algorithm from Damen et al. (2008).

Where to write the code of the algorithm?

The algorithms are all located in the same package :fr.ign.cogit.cartagen.algorithms. The package contains several subpackages that gather “similar” algorithms even though the categorization is quite rough. In our example, the algorithm amalgamates a group of close buildings in a building block, so we choose to add it in the fr.ign.cogit.cartagen.algorithms.block package. This package contains a class (fr.ign.cogit.cartagen.algorithms.block.BuildingAggregation) for building aggregation (quite similar to amalgamation) algorithms in which we will be adding the new algorithm.

Is there a template to write an algorithm in CartAGen?

No, there is no template to write the code of a new algorithm in CartAGen. The algorithm can be coded as a public method in a class that contains several algorithms, as a static class (that’s the chosen way in this tutorial but not the best way), or as a class. However, there are some guidelines to make the algorithm useful for all the users of CartAGen:

    public static Collection<IBuilding> computeMorphologicalAmalgamation(Collection<IBuilding> buildings, double bufferSize){
    // initialise
    Collection<IBuilding> outCollection = new HashSet<>();
    Collection<IPolygon> clusters = new HashSet<>();
    IMultiSurface<IPolygon> multiPolygon = GeometryEngine.getFactory()
        .createMultiPolygon();
    for (IBuilding building : buildings)
      multiPolygon.add(building.getGeom());

    MorphologyTransform morph = new MorphologyTransform(bufferSize, 20);
    morph.setCapForm(BufferParameters.CAP_FLAT);
    IMultiSurface<IPolygon> closedGeom = morph
        .closingMultiPolygon(multiPolygon);
    IGeometry merged = morph.opening(closedGeom);

    if (merged instanceof IPolygon) {
      clusters.add((IPolygon) merged);
    } else if (merged instanceof IMultiSurface) {
      for (IPolygon simple : ((IMultiSurface<IPolygon>) merged).getList())
        clusters.add(simple);
    }

    // from the collection of output polygon, create a new building feature
    // from each of these polygons
    for (IPolygon clusterPolygon : clusters) {

      IPolygon simplified = edgeRemovalSimplification(clusterPolygon,
          edgeLength);

      // simplify the polygon by removing small edges
      IBuilding newBuilding = CartAGenDoc.getInstance().getCurrentDataset()
          .getCartAGenDB().getGeneObjImpl().getCreationFactory()
          .createBuilding(simplified);
      outCollection.add(newBuilding);
    }
    return outCollection;
    }

Documenting the added algorithm

Of course, comments should be added in the code, as much as possible, to document the algorithm (see the example below).

  /**
   * Algorithms to amalgamate a collection of buildings into one (or several)
   * square amalgamated polygon, using morphological operators. The algorithm is
   * an implementation of the paper from Damen et al. (2008, ICA Workshop in
   * Montpellier). Here, the sequence of operators is closure, then opening,
   * then edge removal.
   * 
   * @param buildings
   * @param bufferSize the size of the buffer for the dilation/erosion
   *          operations.
   * @param edgeLength the minimum length for final edges of the polygon
   *          (smaller edges are removed).
   * @return
   */

The website that describes and documents the CartAGen project (i.e. this website), also contains descriptions of the available algorithms, so the addition of a new algorithm should involve the addition of a new webpage to document the algorithm. You can find here the page that documents the Damen et al. algorithm used above as an example.

See Also