package org.geotools.renderer.label;
import org.geotools.renderer.style.TextStyle2D;
import org.geotools.styling.TextSymbolizer.PolygonAlignOptions;
import com.vividsolutions.jts.algorithm.MinimumDiameter;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.prep.PreparedGeometry;
/**
* Helper class that keeps the state of the alternate polygon labelling angle to avoid its (sometime
* expensive) computation as the labeller tries different labelling positions
*
* @author Andrea Aime - GeoSolutions
*/
class TextStyle2DExt extends TextStyle2D {
Double alternateRotation;
LabelCacheItem item;
public TextStyle2DExt(LabelCacheItem item) {
super(item.getTextStyle());
this.item = item;
}
void setupPolygonAlign(PreparedGeometry pg) {
if (item.getPolygonAlign() == PolygonAlignOptions.NONE)
return;
}
boolean flipRotation(Geometry geometry) {
if (item.getPolygonAlign() == PolygonAlignOptions.NONE) {
return false;
}
// lazily compute rotation
if (alternateRotation == null) {
double radians = 0;
if (item.getPolygonAlign() == PolygonAlignOptions.ORTHO) {
radians = calcPolygonAlignOrthoAngle(geometry);
} else if (item.getPolygonAlign() == PolygonAlignOptions.MBR) {
radians = calcPolygonAlignMBRAngle(geometry);
}
alternateRotation = radians;
}
// swap the two rotations
double temp = getRotation();
setRotation(alternateRotation);
alternateRotation = temp;
return true;
}
double calcPolygonAlignOrthoAngle(Geometry geometry) {
Envelope envelope = geometry.getEnvelopeInternal();
if (envelope.getHeight() > envelope.getWidth()) {
return -(Math.PI / 2);
} else {
return 0;
}
}
double calcPolygonAlignMBRAngle(Geometry geometry) {
// use JTS MinimumDiameter class to calc MBR
Geometry mbr = new MinimumDiameter(geometry).getMinimumRectangle();
// calc angle from the longest side of the MBR
Coordinate[] coordinates = mbr.getCoordinates();
double dx, dy;
if (coordinates[0].distance(coordinates[1]) > coordinates[1].distance(coordinates[2])) {
dx = coordinates[1].x - coordinates[0].x;
dy = coordinates[1].y - coordinates[0].y;
} else {
dx = coordinates[2].x - coordinates[1].x;
dy = coordinates[2].y - coordinates[1].y;
}
double angle = Math.atan(dy / dx);
// make sure we turn PI/2 into -PI/2, we don't want some labels looking straight up
// and some others straight down, when almost vertical they should all be oriented
// on the same side
if (Math.abs(angle - Math.PI / 2) < Math.PI / 180.0) {
angle = -Math.PI / 2 + Math.abs(angle - Math.PI / 2);
}
return angle;
}
}