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

Reply via email to