2

I read How can I label the coordinate position of the grid coordinate lines but I still do not understand how to use the LineFeatureBuilder class to label the grid lines. Could someone let me know how do I use this class in my code to get the labels? Code creating the lines:

        List<OrthoLineDef> lineDefs =
                Arrays.asList(
                        new OrthoLineDef(LineOrientation.VERTICAL, 2, 10.0),
                        new OrthoLineDef(LineOrientation.HORIZONTAL, 2, 10.0)
                );
        double vertexSpacing = 0.1;
        SimpleFeatureSource grid = Lines.createOrthoLines(gridBounds, lineDefs, vertexSpacing);
....
        Style latlonStyle = SLD.createLineStyle( strokeColor, strokeWidth );
3

I wrote a blog post about this a while back, 1st you need to override org.geotools.grid.GridFeatureBuilder to add the X or Y values to the lines (so you can draw them later):

package com.ianturton.cookbook.utilities.gridsupport;

import java.text.Format;
import java.util.Map;

import org.geotools.grid.GridElement;
import org.geotools.grid.GridFeatureBuilder;
import org.geotools.grid.ortholine.LineOrientation;
import org.geotools.grid.ortholine.OrthoLine;
import org.geotools.measure.CoordinateFormat;
import org.locationtech.jts.geom.Coordinate;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.referencing.cs.CoordinateSystem;

public class LineFeatureBuilder extends GridFeatureBuilder {
  /** Default feature TYPE name: "linegrid" */
  public static final String DEFAULT_TYPE_NAME = "linegrid";

  /** Name used for the integer id attribute: "id" */
  public static final String ID_ATTRIBUTE_NAME = "id";

  /**
   * Name of the Integer level attribute ("level")
   */
  public static final String LEVEL_ATTRIBUTE_NAME = "level";

  /**
   * Name of the Object value attribute ("value")
   */
  public static final String VALUE_ATTRIBUTE_NAME = "value";

  public static final String VALUE_LABEL_NAME = "label";

  protected int id;
  private SimpleFeatureType type;
  private CoordinateFormat formatter;
  private Format xFormat;
  private Format yFormat;
  private String xUnit;
  private String yUnit;

  public LineFeatureBuilder(SimpleFeatureType type2) {
    super(type2);
    this.type = type2;
    formatter = new CoordinateFormat();
    formatter.setNumberPattern("##0.00");
    formatter.setAnglePattern("DD.dd");

    formatter.setCoordinateReferenceSystem(type.getCoordinateReferenceSystem());
    xFormat = formatter.getFormat(0);
    yFormat = formatter.getFormat(1);
    CoordinateSystem coordinateSystem = type.getCoordinateReferenceSystem().getCoordinateSystem();
    xUnit = "" + coordinateSystem.getAxis(0).getUnit().toString();
    yUnit = "" + coordinateSystem.getAxis(1).getUnit().toString();
  }

  @Override
  public void setAttributes(GridElement el, Map<String, Object> attributes) {
    if (el instanceof OrthoLine) {
      OrthoLine orthoLine = (OrthoLine) el;
      attributes.put(ID_ATTRIBUTE_NAME, ++id);
      attributes.put(LEVEL_ATTRIBUTE_NAME, orthoLine.getLevel());

      Coordinate v0 = orthoLine.getVertices()[0];
      Double value = null;
      String label = "";
      if (orthoLine.getOrientation() == LineOrientation.HORIZONTAL) {
        value = v0.y;
        label = yFormat.format(v0.y) + yUnit;
      } else {
        value = v0.x;
        label = xFormat.format(v0.x) + xUnit;
      }
      attributes.put(VALUE_ATTRIBUTE_NAME, value);
      attributes.put(VALUE_LABEL_NAME, label);

    } else {
      throw new IllegalArgumentException("Expected an instance of OrthoLine");
    }
  }

}

Then you can create the "grid" using something like:

ReferencedEnvelope bounds = ReferencedEnvelope.create(new Envelope(xMin, xMax, yMin, yMax),
    coordinateReferenceSystem);

SimpleFeatureType type = (SimpleFeatureType) GridUtilities.buildType(coordinateReferenceSystem);
List<OrthoLineDef> lineDefs = Arrays.asList(
    // vertical (longitude) lines
    new OrthoLineDef(LineOrientation.VERTICAL, 2, xStep),
    // horizontal (latitude) lines
    new OrthoLineDef(LineOrientation.HORIZONTAL, 2, yStep));

// Specify vertex spacing to get "densified" polygons
double vertexSpacing = 0.1;
grid = Lines.createOrthoLines(bounds, lineDefs, vertexSpacing, new LineFeatureBuilder(type));

The final trick is to make the style draw the labels as well as the lines:

  Style red = SLD.createLineStyle(Color.red, 1.0f);
  ((LineSymbolizer)red.featureTypeStyles().get(0).rules()
    .get(0).symbolizers().get(0)).getStroke().setOpacity(ff.literal(0.5));
  layer = new FeatureLayer(featureSource, style);
  layer.getBounds().getCoordinateReferenceSystem();
  ReferencedEnvelope gridBounds = layer.getBounds();

  StyleBuilder sb = new StyleBuilder();
  java.awt.Font font = java.awt.Font.decode("Arial");
  TextSymbolizer text = sb.createTextSymbolizer(Color.red,
  sb.createFont(font), "label");

  LabelPlacement lp = sb.createLinePlacement(ff.literal(4));
  text.setLabelPlacement(lp);
  red.featureTypeStyles().get(0).rules().get(0).symbolizers().add(text);
  Layer gridLayer = new FeatureLayer(grid, red);

Then add gridLayer to your map with all your other layers.

Update

Gridutilities.buildType:

  private static FeatureType buildType(CoordinateReferenceSystem crs) {
    SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder();
    tb.setName("grid");
    tb.add(LineFeatureBuilder.DEFAULT_GEOMETRY_ATTRIBUTE_NAME, LineString.class, crs);
    tb.add(LineFeatureBuilder.ID_ATTRIBUTE_NAME, Integer.class);
    tb.add(LineFeatureBuilder.LEVEL_ATTRIBUTE_NAME, Integer.class);
    tb.add(LineFeatureBuilder.VALUE_LABEL_NAME, String.class);
    tb.add(LineFeatureBuilder.VALUE_ATTRIBUTE_NAME, Double.class);
    return tb.buildFeatureType();
  }
3
  • Thanks Ian, I am not able to find GridUtilities import or dependency package anywhere. How do I import into java class and add GridUtilities to maven then? I have searched on internet since this is the only way to research I have available with no luck – Isidora Apr 9 '20 at 19:30
  • I was able to plot the lat/lon values in graticule every 10 degrees. I would like to: place latitude labels on both sides of map instead of center, longitude values at the bottom of the map, lats and lons values to start at 0 without decimals, and have labels every 30 degrees. Any hint on where to start researching the desired formatter? – Isidora Apr 13 '20 at 23:59
  • You can adjust the number of labels by adding a filter to the style, and there is a round function to remove decimals - see the GeoServer SLD documentation for examples or other questions on this site – Ian Turton Apr 14 '20 at 10:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.