Andrea Aime ha scritto:
Jody Garnett ha scritto:
On 17/06/2010, at 10:36 PM, Andrea Aime wrote:
Let's say the renderer would become... more aware of dpi.
It's actually already considering the dpi hint when it comes to compute
the scale.
The rescale visitor would not go, that's actually the bit of code I
want to use to perform dpi rescaling (just as the uom rescale visitor,
sitting right in the same package as yours, it visible to everybody,
and used internally in the renderer)
Got it; we may need to offer a bit more fine grain control over time;
but if you can use it as is more the better.
The result is actually not exactly the same... and I think I know the
reasons: there has been no rescaling on the text symbolizer format
options, in particular the space around factor.
I guess I'll have to modify the rescaler code to take that into account
as well.
Found out that actually the issue were in the missing halo size rescaling.
The attached patch fixes it, as well as moving all the vendor option
keys and default values in TextSymbolizer, turning them into more
visible documentation for the user.
Here is another sample, normal and rescaled:
http://sigma.openplans.org/~aaime/normalDpi.png
http://sigma.openplans.org/~aaime/rescaledDpi.png
Ok to apply?
Cheers
Andrea
--
Andrea Aime
OpenGeo - http://opengeo.org
Expert service straight from the developers.
diff --git a/modules/library/api/src/main/java/org/geotools/styling/TextSymbolizer.java b/modules/library/api/src/main/java/org/geotools/styling/TextSymbolizer.java
index 140e7bb..a0515cf 100644
--- a/modules/library/api/src/main/java/org/geotools/styling/TextSymbolizer.java
+++ b/modules/library/api/src/main/java/org/geotools/styling/TextSymbolizer.java
@@ -87,6 +87,163 @@ import org.opengis.filter.expression.Expression;
* @source $URL$
*/
public interface TextSymbolizer extends org.opengis.style.TextSymbolizer,Symbolizer {
+
+
+ /**
+ * If true, geometries with the same labels are grouped and considered a single entity to be
+ * labeled. This allows to avoid or control repeated labels
+ */
+ public static String GROUP_KEY = "group";
+
+ /**
+ * Default grouping value, false
+ */
+ public boolean DEFAULT_GROUP = false;
+
+ /**
+ * The minimum distance between two labels, in pixels
+ */
+ public static String SPACE_AROUND_KEY = "spaceAround";
+
+ /**
+ * By default, don't add space around labels
+ */
+ public static int DEFAULT_SPACE_AROUND = 0;
+
+ /**
+ * The distance, in pixel, a label can be displaced from its natural position in an attempt to
+ * find a position that does not conflict with already drawn labels.
+ */
+ public static String MAX_DISPLACEMENT_KEY = "maxDisplacement";
+
+ /**
+ * Default max displacement
+ */
+ public static int DEFAULT_MAX_DISPLACEMENT = 0;
+
+ /**
+ * Minimum distance between two labels in the same label group. To be used when both
+ * displacement and repeat are used to avoid having two labels too close to each other
+ */
+ public static String MIN_GROUP_DISTANCE_KEY = "minGroupDistance";
+
+ /**
+ * Default min distance between labels in the same group (-1 means no min
+ * distance)
+ */
+ public static int DEFAULT_MIN_GROUP_DISTANCE = -1;
+
+ /**
+ * When positive it's the desired distance between two subsequent labels on a "big" geometry.
+ * Works only on lines at the moment. If zero only one label is drawn no matter how big the
+ * geometry is
+ */
+ public static String LABEL_REPEAT_KEY = "repeat";
+
+ /**
+ * Default repetition distance for labels (<= 0 -> no repetition)
+ */
+ public static int DEFAULT_LABEL_REPEAT = 0;
+
+ /**
+ * When false, only the biggest geometry in a group is labelled (the biggest is obtained by
+ * merging, when possible, the original geometries). When true, also the smaller items in the
+ * group are labeled. Works only on lines at the moment.
+ */
+ public static String LABEL_ALL_GROUP_KEY = "labelAllGroup";
+
+ /**
+ * If in case of grouping all resulting lines have to be labelled
+ */
+ public static boolean DEFAULT_LABEL_ALL_GROUP = false;
+
+ /**
+ * When false does not allow labels on lines to get beyond the beginning/end of the line.
+ * By default a partial overrun is tolerated, set to false to disallow it.
+ */
+ public static String ALLOW_OVERRUNS_KEY = "allowOverruns";
+
+ /**
+ * We allow labels that are longer than the line to appear by default
+ */
+ public static boolean DEFAULT_ALLOW_OVERRUNS = true;
+
+ /**
+ * If, in case of grouping, self overlaps have to be taken into account and
+ * removed (expensive!)
+ */
+ public static boolean DEFAULT_REMOVE_OVERLAPS = false;
+
+ /**
+ * When true activates curved labels on linear geometries. The label will follow the shape of
+ * the current line, as opposed to being drawn a tangent straight line
+ */
+ public static String FOLLOW_LINE_KEY = "followLine";
+
+ /**
+ * If labels with a line placement should follow the line shape or be just
+ * tangent
+ */
+ public static boolean DEFAULT_FOLLOW_LINE = false;
+
+ /**
+ * When drawing curved labels, max allowed angle between two subsequent characters. Higher
+ * angles may cause disconnected words or overlapping characters
+ */
+ public static String MAX_ANGLE_DELTA_KEY = "maxAngleDelta";
+
+ /**
+ * When label follows line, the max angle change between two subsequent characters, keeping it
+ * low avoids chars overlaps. When the angle is exceeded the label placement will fail.
+ */
+ public static double DEFAULT_MAX_ANGLE_DELTA = 22.5;
+
+ /**
+ * Number of pixels are which a long label should be split into multiple lines. Works on all
+ * geometries, on lines it is mutually exclusive with the followLine option
+ */
+ public static String AUTO_WRAP_KEY = "autoWrap";
+
+ /**
+ * Auto wrapping long labels default
+ */
+ public static final int DEFAULT_AUTO_WRAP = 0;
+
+ /**
+ * When true forces labels to a readable orientation, when false they make follow the line
+ * orientation even if that means the label will look upside down (useful when using
+ * TTF symbol fonts to add direction markers along a line)
+ */
+ public static String FORCE_LEFT_TO_RIGHT_KEY = "forceLeftToRight";
+
+ /**
+ * Force labels to a readable orientation (so that they don't look "upside down")
+ */
+ public static final boolean DEFAULT_FORCE_LEFT_TO_RIGHT = true;
+
+ /**
+ * Enables conflict resolution (default, true) meaning no two labels will be allowed to
+ * overlap. Symbolizers with conflict resolution off are considered outside of the
+ * conflict resolution game, they don't reserve area and can overlap with other labels.
+ */
+ public static String CONFLICT_RESOLUTION_KEY = "conflictResolution";
+
+ /**
+ * By default, put each label in the conflict resolution map
+ */
+ public static final boolean DEFAULT_CONFLICT_RESOLUTION = true;
+
+ /**
+ * Sets the percentage of the label that must sit inside the geometry to allow drawing
+ * the label. Works only on polygons.
+ */
+ public static String GOODNESS_OF_FIT_KEY = "goodnessOfFit";
+
+ /**
+ * Default value for the goodness of fit threshold
+ */
+ public static final double DEFAULT_GOODNESS_OF_FIT = 0.5;
+
/**
* Returns the expression that will be evaluated to determine what text is
* displayed.
diff --git a/modules/library/main/src/main/java/org/geotools/styling/visitor/RescaleStyleVisitor.java b/modules/library/main/src/main/java/org/geotools/styling/visitor/RescaleStyleVisitor.java
index 1f23b6c..e751699 100644
--- a/modules/library/main/src/main/java/org/geotools/styling/visitor/RescaleStyleVisitor.java
+++ b/modules/library/main/src/main/java/org/geotools/styling/visitor/RescaleStyleVisitor.java
@@ -16,14 +16,28 @@
*/
package org.geotools.styling.visitor;
+import java.util.Map;
+
+import javax.measure.quantity.Length;
+import javax.measure.unit.NonSI;
+import javax.measure.unit.Unit;
+
+import static org.geotools.styling.TextSymbolizer.*;
+
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.styling.Displacement;
import org.geotools.styling.ExternalGraphic;
import org.geotools.styling.Font;
import org.geotools.styling.Graphic;
+import org.geotools.styling.LabelPlacement;
+import org.geotools.styling.LinePlacement;
import org.geotools.styling.Mark;
+import org.geotools.styling.PointPlacement;
import org.geotools.styling.Stroke;
import org.geotools.styling.Symbol;
+import org.geotools.styling.TextSymbolizer;
+import org.geotools.util.Converters;
+import org.jdom.Text;
import org.opengis.filter.FilterFactory2;
import org.opengis.filter.expression.Expression;
import org.opengis.filter.expression.Literal;
@@ -82,7 +96,14 @@ public class RescaleStyleVisitor extends DuplicatingStyleVisitor {
* @param expr
* @return expr multiplied by the provided scale
*/
- protected Expression rescale( Expression expr ){
+ protected Expression rescale( Expression expr ) {
+ if(expr == null) {
+ return null;
+ }
+ if(expr == Expression.NIL) {
+ return Expression.NIL;
+ }
+
Expression rescale = ff.multiply( scale, expr );
if( expr instanceof Literal && scale instanceof Literal){
double constant = (double) rescale.evaluate(null, Double.class);
@@ -111,18 +132,6 @@ public class RescaleStyleVisitor extends DuplicatingStyleVisitor {
pages.push(copy);
}
- /** Increase font size */
- protected Font copy(Font font) {
- if( font == null) return font;
-
- Expression fontFamily = copy( font.getFontFamily() );
- Expression fontStyle = copy( font.getFontStyle() );
- Expression fontWeight = copy( font.getFontWeight() );
- Expression fontSize = rescale( font.getFontSize() );
- Font copy = sf.createFont(fontFamily, fontStyle, fontWeight, fontSize);
- return copy;
- }
-
/** Make graphics (such as used with PointSymbolizer) bigger */
public void visit(Graphic gr) {
Graphic copy = null;
@@ -173,5 +182,87 @@ public class RescaleStyleVisitor extends DuplicatingStyleVisitor {
pages.push(copy);
}
+
+ @Override
+ public void visit(TextSymbolizer text) {
+ super.visit(text);
+ TextSymbolizer copy = (TextSymbolizer) pages.peek();
+
+ // rescales fonts
+ Font[] fonts = copy.getFonts();
+ for (Font font : fonts) {
+ font.setSize(rescale(font.getSize()));
+ }
+ copy.setFonts(fonts);
+
+ // rescales label placement
+ LabelPlacement placement = copy.getLabelPlacement();
+ if (placement instanceof PointPlacement) {
+ // rescales point label placement
+ PointPlacement pointPlacement = (PointPlacement) placement;
+ Displacement disp = pointPlacement.getDisplacement();
+ if (disp != null) {
+ disp.setDisplacementX(rescale(disp.getDisplacementX()));
+ disp.setDisplacementY(rescale(disp.getDisplacementY()));
+ pointPlacement.setDisplacement(disp);
+ }
+ } else if (placement instanceof LinePlacement) {
+ // rescales line label placement
+ LinePlacement linePlacement = (LinePlacement) placement;
+ linePlacement.setGap(rescale(linePlacement.getGap()));
+ linePlacement.setInitialGap(rescale(linePlacement.getInitialGap()));
+ linePlacement.setPerpendicularOffset(rescale(linePlacement.getPerpendicularOffset()));
+ }
+ copy.setLabelPlacement(placement);
+
+ // rescale the halo
+ if(copy.getHalo() != null) {
+ copy.getHalo().setRadius(rescale(copy.getHalo().getRadius()));
+ }
+
+ // deal with the format options specified in pixels
+ Map<String, String> options = copy.getOptions();
+ rescaleOption(options, SPACE_AROUND_KEY, DEFAULT_SPACE_AROUND);
+ rescaleOption(options, MAX_DISPLACEMENT_KEY, DEFAULT_MAX_DISPLACEMENT);
+ rescaleOption(options, MIN_GROUP_DISTANCE_KEY, DEFAULT_MIN_GROUP_DISTANCE);
+ rescaleOption(options, LABEL_REPEAT_KEY, DEFAULT_LABEL_REPEAT);
+ rescaleOption(options, AUTO_WRAP_KEY, DEFAULT_AUTO_WRAP);
+ }
+
+ /**
+ * Rescales the specified vendor option
+ * @param options
+ * @param key
+ * @param defaultAutoWrap
+ * @param value
+ */
+ protected void rescaleOption(Map<String, String> options, String key, double defaultValue) {
+ double scaleFactor = (double) scale.evaluate(null, Double.class);
+ if(options.get(key) != null) {
+ double rescaled = Converters.convert(options.get(key), Double.class) * scaleFactor;
+ options.put(key, String.valueOf(rescaled));
+ } else if(defaultValue != 0) {
+ options.put(key, String.valueOf(defaultValue * scaleFactor));
+ }
+
+ };
+
+ /**
+ * Rescales the specified vendor option
+ * @param options
+ * @param key
+ * @param defaultAutoWrap
+ * @param value
+ */
+ protected void rescaleOption(Map<String, String> options, String key, int defaultValue) {
+ double scaleFactor = (double) scale.evaluate(null, Double.class);
+ if(options.get(key) != null) {
+ int rescaled = (int) Math.round(Converters.convert(options.get(key), Double.class) * scaleFactor);
+ options.put(key, String.valueOf(rescaled));
+ } else if(defaultValue != 0) {
+ options.put(key, String.valueOf((int) Math.round(defaultValue * scaleFactor)));
+ }
+
+ };
}
diff --git a/modules/library/main/src/main/java/org/geotools/styling/visitor/UomRescaleStyleVisitor.java b/modules/library/main/src/main/java/org/geotools/styling/visitor/UomRescaleStyleVisitor.java
index 7305dcf..cf5e3a8 100644
--- a/modules/library/main/src/main/java/org/geotools/styling/visitor/UomRescaleStyleVisitor.java
+++ b/modules/library/main/src/main/java/org/geotools/styling/visitor/UomRescaleStyleVisitor.java
@@ -250,6 +250,12 @@ public class UomRescaleStyleVisitor extends DuplicatingStyleVisitor {
mapScale, uom));
}
copy.setLabelPlacement(placement);
+
+ // rescale the halo
+ if(copy.getHalo() != null) {
+ copy.getHalo().setRadius(rescale(copy.getHalo().getRadius(), mapScale, uom));
+ }
+
copy.setUnitOfMeasure(NonSI.PIXEL);
}
}
diff --git a/modules/library/render/src/main/java/org/geotools/renderer/label/LabelCacheImpl.java b/modules/library/render/src/main/java/org/geotools/renderer/label/LabelCacheImpl.java
index a1f036f..8a2a7a4 100644
--- a/modules/library/render/src/main/java/org/geotools/renderer/label/LabelCacheImpl.java
+++ b/modules/library/render/src/main/java/org/geotools/renderer/label/LabelCacheImpl.java
@@ -16,6 +16,8 @@
*/
package org.geotools.renderer.label;
+import static org.geotools.styling.TextSymbolizer.*;
+
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
@@ -77,37 +79,6 @@ import com.vividsolutions.jts.precision.EnhancedPrecisionOp;
* <p>{...@link TextSymbolizer#getPriority()} OGC Expression controls a label priority.</p>
* <p>A label with high priority will be drawn before others, increasing its likeliness
* to appear on the screen</p>
- *
- * <h2>Vendor options</h2>
- * <p>{...@link TextSymbolizer#getOptions()} contains a map of vendor specific options
- * other than priority which are not part of the SLD specification. Here is a list
- * of their names, default values, and meaning:
- * <ul>
- * <li><code>spaceAround</code> (0): the minimum distance between two labels, in pixels</li>
- * <li><code>group</code> (false): if true, geometries with the same labels are grouped and
- * considered a single entity to be labeled. This allows to avoid or control repeated labels</li>
- * <li><code>labelAllGroup</code> (false): when false, in a group only the biggest geometry is labelled
- * (the biggest is obtained by merging, when possible, the original geometries). When true, also the
- * smaller items in the group are labelled. Works only on lines at the moment</li>
- * <li><code>maxDisplacement</code> (50): the distance, in pixel, a label can be displaced
- * from its natural position in an attempt to find a position that does not conflict with
- * already drawn labels. At the moment this works only on lines</li>.
- * <li><code>repeat</code> (0): when positive it's the desired distance between two subsequent labels
- * on a "big" geometry. Works only on lines atm, if zero only one label is drawn no matter how big
- * the geometry is</li>
- * <li><code>minGroupDistance</code> (0): minimum distance between two labels in the same label group.
- * To be used when both displacement and repeat are used to avoid having two labels too close to
- * each other</li>
- * <li><code>allowOvveruns</code> (true): when false does not allow labels on lines to get beyond the
- * beginning/end of the line. By default a partial overrun is tolerated, set to false to disallow it.</li>
- * <li><code>followLine</code> (false): when true activates curved labels on linear geometries. The label
- * will follow the shape of the current line, as opposed to being drawn a tangent straight line</li>
- * <li><code>maxAngleDelta</code> (22.5): when drawing curved labels, max allowed angle between
- * two subsequent characters. Higher angles may cause disconnected words or overlapping characters</li>
- * <li><code>autoWrap</code> (false): number of pixels are which a long label should be split into
- * multiple lines. Works on all geometries, on lines it is mutually exclusive with the
- * <code>followLine<code> option.</li>
- * </ul>
*
* @author jeichar
* @author dblasby
@@ -120,6 +91,11 @@ public final class LabelCacheImpl implements LabelCache {
static final Logger LOGGER = Logging.getLogger(LabelCacheImpl.class);
public double DEFAULT_PRIORITY = 1000.0;
+
+ /**
+ * The angle delta at which we switch from curved rendering to straight rendering
+ */
+ public static double MIN_CURVED_DELTA = Math.PI / 60;
/** Map<label, LabelCacheItem> the label cache */
protected Map<String, LabelCacheItem> labelCache = new HashMap<String, LabelCacheItem>();
@@ -130,61 +106,6 @@ public final class LabelCacheImpl implements LabelCache {
/** List of reserved areas of the screen for which labels should fear to tread */
private List<Rectangle2D> reserved = new ArrayList<Rectangle2D>();
- // what to do if there's no grouping option
- public boolean DEFAULT_GROUP = false;
-
- // by default, don't add space around labels
- public int DEFAULT_SPACE_AROUND = 0;
-
- // default max displacement
- public int DEFAULT_MAX_DISPLACEMENT = 0;
-
- // default max displacement when labeling points
- public int DEFAULT_MAX_DISPLACEMENT_POINT = 0;
-
- // default min distance between labels in the same group (-1 means no min
- // distance)
- public int DEFAULT_MIN_GROUP_DISTANCE = -1;
-
- // default repetition distance for labels (<= 0 -> no repetition)
- public int DEFAULT_LABEL_REPEAT = 0;
-
- // if in case of grouping all resulting lines have to be labelled
- public boolean DEFAULT_LABEL_ALL_GROUP = false;
-
- // we allow labels that are longer than the line to appear by default
- public boolean DEFAULT_ALLOW_OVERRUNS = true;
-
- // if, in case of grouping, self overlaps have to be taken into account and
- // removed (expensive!)
- public boolean DEFAULT_REMOVE_OVERLAPS = false;
-
- // if labels with a line placement should follow the line shape or be just
- // tangent
- public boolean DEFAULT_FOLLOW_LINE = false;
-
- // when label follows line, the max angle change between two subsequent
- // characters, keeping
- // it low avoids chars overlaps. When the angle is exceeded the label
- // placement will fail.
- public double DEFAULT_MAX_ANGLE_DELTA = 22.5;
-
- // The angle delta at which we switch from curved rendering to straight
- // rendering
- static final double MIN_CURVED_DELTA = Math.PI / 60;
-
- // Auto wrapping long labels default
- static final int DEFAULT_AUTO_WRAP = 0;
-
- // Force labels to a readable orientation (so that they don't look "upside down")
- static final boolean DEFAULT_FORCE_LEFT_TO_RIGHT = true;
-
- // By default, put each label in the conflict resolution map
- static final boolean DEFAULT_CONFLICT_RESOLUTION = true;
-
- // Default value for the goodness of fit threshold
- static final double DEFAULT_GOODNESS_OF_FIT = 0.5;
-
// Anchor candidate values used when looping to find a point label that can be drawn
static final double[] RIGHT_ANCHOR_CANDIDATES = new double[] {0,0.5, 0,0, 0,1};
static final double[] MID_ANCHOR_CANDIDATES = new double[] {0.5,0.5, 0,0.5, 1,0.5};
@@ -332,7 +253,7 @@ public final class LabelCacheImpl implements LabelCache {
return; // dont label something with nothing!
}
double priorityValue = getPriority(symbolizer, feature);
- boolean group = getBooleanOption(symbolizer, "group", false);
+ boolean group = getBooleanOption(symbolizer, TextSymbolizer.GROUP_KEY, false);
if (!(group)) {
LabelCacheItem item = buildLabelCacheItem(layerId, symbolizer, feature, shape,
scaleRange, label, priorityValue);
@@ -388,25 +309,25 @@ public final class LabelCacheImpl implements LabelCache {
LabelCacheItem item = new LabelCacheItem(layerId, textStyle, shape, label);
item.setPriority(priorityValue);
- item.setSpaceAround(getIntOption(symbolizer, "spaceAround", DEFAULT_SPACE_AROUND));
- item.setMaxDisplacement(getIntOption(symbolizer, "maxDisplacement",
+ item.setSpaceAround(getIntOption(symbolizer, SPACE_AROUND_KEY, DEFAULT_SPACE_AROUND));
+ item.setMaxDisplacement(getIntOption(symbolizer, MAX_DISPLACEMENT_KEY,
DEFAULT_MAX_DISPLACEMENT));
- item.setMinGroupDistance(getIntOption(symbolizer, "minGroupDistance",
+ item.setMinGroupDistance(getIntOption(symbolizer, MIN_GROUP_DISTANCE_KEY,
DEFAULT_MIN_GROUP_DISTANCE));
- item.setRepeat(getIntOption(symbolizer, "repeat", DEFAULT_LABEL_REPEAT));
- item.setLabelAllGroup(getBooleanOption(symbolizer, "labelAllGroup",
+ item.setRepeat(getIntOption(symbolizer, LABEL_REPEAT_KEY, DEFAULT_LABEL_REPEAT));
+ item.setLabelAllGroup(getBooleanOption(symbolizer, LABEL_ALL_GROUP_KEY,
DEFAULT_LABEL_ALL_GROUP));
item.setRemoveGroupOverlaps(getBooleanOption(symbolizer, "removeOverlaps",
DEFAULT_REMOVE_OVERLAPS));
- item.setAllowOverruns(getBooleanOption(symbolizer, "allowOverruns",
+ item.setAllowOverruns(getBooleanOption(symbolizer, ALLOW_OVERRUNS_KEY,
DEFAULT_ALLOW_OVERRUNS));
- item.setFollowLineEnabled(getBooleanOption(symbolizer, "followLine", DEFAULT_FOLLOW_LINE));
- double maxAngleDelta = getDoubleOption(symbolizer, "maxAngleDelta", DEFAULT_MAX_ANGLE_DELTA);
+ item.setFollowLineEnabled(getBooleanOption(symbolizer, FOLLOW_LINE_KEY, DEFAULT_FOLLOW_LINE));
+ double maxAngleDelta = getDoubleOption(symbolizer, MAX_ANGLE_DELTA_KEY, DEFAULT_MAX_ANGLE_DELTA);
item.setMaxAngleDelta(Math.toRadians(maxAngleDelta));
- item.setAutoWrap(getIntOption(symbolizer, "autoWrap", DEFAULT_AUTO_WRAP));
- item.setForceLeftToRightEnabled(getBooleanOption(symbolizer, "forceLeftToRight", DEFAULT_FORCE_LEFT_TO_RIGHT));
- item.setConflictResolutionEnabled(getBooleanOption(symbolizer, "conflictResolution", DEFAULT_CONFLICT_RESOLUTION));
- item.setGoodnessOfFit(getDoubleOption(symbolizer, "goodnessOfFit", DEFAULT_GOODNESS_OF_FIT));
+ item.setAutoWrap(getIntOption(symbolizer, AUTO_WRAP_KEY, DEFAULT_AUTO_WRAP));
+ item.setForceLeftToRightEnabled(getBooleanOption(symbolizer, FORCE_LEFT_TO_RIGHT_KEY, DEFAULT_FORCE_LEFT_TO_RIGHT));
+ item.setConflictResolutionEnabled(getBooleanOption(symbolizer, CONFLICT_RESOLUTION_KEY, DEFAULT_CONFLICT_RESOLUTION));
+ item.setGoodnessOfFit(getDoubleOption(symbolizer, GOODNESS_OF_FIT_KEY, DEFAULT_GOODNESS_OF_FIT));
return item;
}
diff --git a/modules/library/render/src/main/java/org/geotools/renderer/lite/RendererUtilities.java b/modules/library/render/src/main/java/org/geotools/renderer/lite/RendererUtilities.java
index a03637a..005fcf9 100644
--- a/modules/library/render/src/main/java/org/geotools/renderer/lite/RendererUtilities.java
+++ b/modules/library/render/src/main/java/org/geotools/renderer/lite/RendererUtilities.java
@@ -468,7 +468,7 @@ public final class RendererUtilities {
* @param hints
* @return DPI as doubles, to avoid issues with integer trunking in scale computation expression
*/
- private static double getDpi(Map hints) {
+ public static double getDpi(Map hints) {
if( hints!=null && hints.containsKey("dpi") ){
return ((Integer)hints.get("dpi")).intValue();
}else{
diff --git a/modules/library/render/src/main/java/org/geotools/renderer/lite/StreamingRenderer.java b/modules/library/render/src/main/java/org/geotools/renderer/lite/StreamingRenderer.java
index dbc612a..0e04e09 100644
--- a/modules/library/render/src/main/java/org/geotools/renderer/lite/StreamingRenderer.java
+++ b/modules/library/render/src/main/java/org/geotools/renderer/lite/StreamingRenderer.java
@@ -88,6 +88,8 @@ import org.geotools.styling.Rule;
import org.geotools.styling.StyleAttributeExtractor;
import org.geotools.styling.Symbolizer;
import org.geotools.styling.TextSymbolizer;
+import org.geotools.styling.visitor.DuplicatingStyleVisitor;
+import org.geotools.styling.visitor.RescaleStyleVisitor;
import org.geotools.styling.visitor.UomRescaleStyleVisitor;
import org.geotools.util.NumberRange;
import org.geotools.util.Range;
@@ -1809,15 +1811,35 @@ public final class StreamingRenderer implements GTRenderer {
double pixelsPerMeters = RendererUtilities.calculatePixelsPerMeterRatio(scaleDenominator, rendererHints);
UomRescaleStyleVisitor rescaleVisitor = new UomRescaleStyleVisitor(pixelsPerMeters);
for(LiteFeatureTypeStyle fts : lfts) {
- for (int i = 0; i < fts.ruleList.length; i++) {
- rescaleVisitor.visit(fts.ruleList[i]);
- fts.ruleList[i] = (Rule) rescaleVisitor.getCopy();
+ rescaleFeatureTypeStyle(fts, rescaleVisitor);
+ }
+
+ // apply dpi rescale
+ double dpi = RendererUtilities.getDpi(getRendererHints());
+ double standardDpi = RendererUtilities.getDpi(Collections.emptyMap());
+ if(dpi != standardDpi) {
+ double scaleFactor = dpi / standardDpi;
+ RescaleStyleVisitor dpiVisitor = new RescaleStyleVisitor(scaleFactor);
+ for(LiteFeatureTypeStyle fts : lfts) {
+ rescaleFeatureTypeStyle(fts, dpiVisitor);
}
- if(fts.elseRules != null) {
- for (int i = 0; i < fts.elseRules.length; i++) {
- rescaleVisitor.visit(fts.elseRules[i]);
- fts.elseRules[i] = (Rule) rescaleVisitor.getCopy();
- }
+ }
+ }
+
+ /**
+ * Utility method to apply the two rescale visitors without duplicating code
+ * @param fts
+ * @param visitor
+ */
+ void rescaleFeatureTypeStyle(LiteFeatureTypeStyle fts, DuplicatingStyleVisitor visitor) {
+ for (int i = 0; i < fts.ruleList.length; i++) {
+ visitor.visit(fts.ruleList[i]);
+ fts.ruleList[i] = (Rule) visitor.getCopy();
+ }
+ if(fts.elseRules != null) {
+ for (int i = 0; i < fts.elseRules.length; i++) {
+ visitor.visit(fts.elseRules[i]);
+ fts.elseRules[i] = (Rule) visitor.getCopy();
}
}
}
diff --git a/modules/unsupported/shapefile-renderer/src/main/java/org/geotools/renderer/shape/ShapefileRenderer.java b/modules/unsupported/shapefile-renderer/src/main/java/org/geotools/renderer/shape/ShapefileRenderer.java
index 67a0679..c91df60 100644
--- a/modules/unsupported/shapefile-renderer/src/main/java/org/geotools/renderer/shape/ShapefileRenderer.java
+++ b/modules/unsupported/shapefile-renderer/src/main/java/org/geotools/renderer/shape/ShapefileRenderer.java
@@ -100,6 +100,7 @@ import org.geotools.styling.StyleAttributeExtractor;
import org.geotools.styling.Symbolizer;
import org.geotools.styling.TextSymbolizer;
import org.geotools.styling.visitor.DuplicatingStyleVisitor;
+import org.geotools.styling.visitor.RescaleStyleVisitor;
import org.geotools.styling.visitor.UomRescaleStyleVisitor;
import org.geotools.util.NumberRange;
import org.opengis.feature.simple.SimpleFeature;
@@ -376,6 +377,22 @@ public class ShapefileRenderer implements GTRenderer {
rescaleVisitor.visit(elseRuleList.get(j));
elseRuleList.set(j, (Rule) rescaleVisitor.getCopy());
}
+
+ // apply dpi rescale
+ double dpi = RendererUtilities.getDpi(getRendererHints());
+ double standardDpi = RendererUtilities.getDpi(Collections.emptyMap());
+ if(dpi != standardDpi) {
+ double scaleFactor = dpi / standardDpi;
+ RescaleStyleVisitor dpiVisitor = new RescaleStyleVisitor(scaleFactor);
+ for (int j = 0; j < ruleList.size(); j++) {
+ dpiVisitor.visit(ruleList.get(j));
+ ruleList.set(j, (Rule) dpiVisitor.getCopy());
+ }
+ for (int j = 0; j < elseRuleList.size(); j++) {
+ dpiVisitor.visit(elseRuleList.get(j));
+ elseRuleList.set(j, (Rule) dpiVisitor.getCopy());
+ }
+ }
// process the features according to the rules
// TODO: find a better way to declare the scale ranges so that
------------------------------------------------------------------------------
ThinkGeek and WIRED's GeekDad team up for the Ultimate
GeekDad Father's Day Giveaway. ONE MASSIVE PRIZE to the
lucky parental unit. See the prize list and enter to win:
http://p.sf.net/sfu/thinkgeek-promo
_______________________________________________
Geotools-devel mailing list
Geotools-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/geotools-devel