Looks good! On 18/06/2010, at 5:52 AM, Andrea Aime wrote:
> 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