I've been experimenting with orthographic projections and I've run into a problem with the labels.
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.
Answer
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.
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 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 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()));
}
No comments:
Post a Comment