6

I've been experimenting with orthographic projections and I've run into a problem with the labels.

enter image description here

I would like to label the countries but I want the labels to run west-east along the country which isn't (currently) an option in the QGis labeling options.

So, I know I can place them along a line but I lack the patience to draw a line in each country. So I'm looking for an automatic way to draw a line through the centroid of a polygon and to the edges so that I can use it as a label placement line.

By 'label placement line' I mean I need a line that crosses the country that I can use as the basis of my labels so that I can use follow line (parallel I think) in the labeling panel. (see for example this question). So they will be a straight horizontal line in EPSG:4326 but nicely curved in my orthographic projection (+proj=ortho +lat_0=51.470129 +lon_0=-0.452751 +x_0=0 +y_0=0 +a=6371000 +b=6371000 +units=m +no_defs).

Ideally it would be a dense line so it curves when reprojected but I can always run a densify process on the output.

2 Answers 2

8

I am not sure if this is the expected result, but you may try to use this expression from the Field Calculator:

intersection(
 make_line(
  make_point(
   x(centroid($geometry)) - bounds_width($geometry),
   y(centroid($geometry))
   ),
  make_point(
  x(centroid($geometry)) + bounds_width($geometry),
  y(centroid($geometry))
  )
 ),
 $geometry
)

It essentially creates a line from two points, with reference to the centroid of each feature. Then, since the line would exceed the country's boundaries, an intersection with the country itself is done.

This will be the result:

enter image description here

I created it with a Geometry generator from the Style panel (my machine required a lot of time for rendering, so maybe perform a test on a few features before for quickly seeing if it is what you want).

6
  • 2
    I'm still hoping there will be a dedicated website which contains a whole variety of examples on how to use the geometry generator. This might be a good website to add such examples ;)
    – Joseph
    Sep 15, 2017 at 14:42
  • 1
    @Joseph good point! The problem is that they are very specific to the single case, so I don't know if it would be of interest for someone. :) Therefore, I am not sure that a geometry generator would be the best solution for this situation.
    – mgri
    Sep 15, 2017 at 14:51
  • While this definitely looks good, I'm not sure I can use it to attach labels to or apply densification to make it curve when reprojected
    – Ian Turton
    Sep 15, 2017 at 15:06
  • @iant Due to a lack of comprehension, I don't understand how do you want to use the lines (please, could you explain what do you mean with I can use it as a label placement line? Which is the setting you are referring to?). Then, which is the CRS in the image you attached?
    – mgri
    Sep 15, 2017 at 15:28
  • see then update
    – Ian Turton
    Sep 15, 2017 at 15:34
4

I have managed to generate a solution for this using GeoTools which seems to be overkill, so I'm still hoping for a QGis solution.

enter image description here

Basically I use the same math as in @mgri's solution, with a little fiddling around to only use the largest polygon in a country (so that France and the USA work better). As you can see there is now an issue that many smaller countries don't get labelled as the line is too short for the label.

Here is the actual code:

try (SimpleFeatureIterator itr = features.features()) {
  while (itr.hasNext()) {
    SimpleFeature feature = itr.next();
    Collection<Property> props = feature.getProperties();
    for (Property p : props) {
      if (p.getDescriptor() instanceof GeometryDescriptor) {
        Geometry geom = (MultiPolygon) feature.getDefaultGeometry();
        int numGeometries = geom.getNumGeometries();
        if(numGeometries>1) {
          //find largest polygon
          Geometry biggest = null;
          double maxArea = Double.NEGATIVE_INFINITY;
          for(int i=0;i<numGeometries;i++) {
            Geometry g = geom.getGeometryN(i);
            double area = g.getArea();
            if(area>maxArea) {
              biggest =  g;
              maxArea = area;
            }
          }
          geom = biggest;
        }
        Point pt = geom.getCentroid();
        Envelope env = geom.getEnvelopeInternal();
        Coordinate[] coords = new Coordinate[2];
        coords[0] = new Coordinate(env.getMinX(), pt.getY());
        coords[1] = new Coordinate(env.getMaxX(), pt.getY());
        LineString line = gf.createLineString(coords);

        Geometry intersection = line.intersection(geom);
        if (!intersection.isEmpty()) {
          Geometry inter = Densifier.densify(intersection, 0.1);
          builder.set(p.getName(), inter);
        } else {
          builder.set(p.getName(),intersection);
        }
      } else {
        builder.set(p.getName(), p.getValue());
      }

    }
    ret.add(builder.buildFeature(feature.getID()));
  }
2
  • How about skipping the step of intersecting the line with the country polygon?
    – csk
    Sep 20, 2017 at 15:31
  • that might help a little
    – Ian Turton
    Sep 20, 2017 at 15:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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