Hello again folks

On the previous patches I sent regarding UOM support in 2.6.x, I did not include a UomRescaleStyleVisitor class that we are currently using to scale our styles/symbolizers according to the specified unit of measure.

It is currently in our own library, but if you are interested I guess it would be nice to have in GeoTools itself. Check it out.. (attached file)

Cheers
Milton


--

Milton Jonathan
Grupo GIS e Meio Ambiente
Tecgraf/PUC-Rio
Tel: +55-21-3527-2502
package org.tecgraf.tdk.style.visitor;

import javax.measure.converter.UnitConverter;
import javax.measure.quantity.Length;
import javax.measure.unit.NonSI;
import javax.measure.unit.SI;
import javax.measure.unit.Unit;

import org.geotools.styling.Graphic;
import org.geotools.styling.LineSymbolizer;
import org.geotools.styling.PointSymbolizer;
import org.geotools.styling.PolygonSymbolizer;
import org.geotools.styling.Stroke;
import org.geotools.styling.visitor.DuplicatingStyleVisitor;
import org.opengis.filter.expression.Expression;

/**
 * Visitor used for rescaling a Style given a map scale (e.g., meters per pixel)
 * and taking into consideration the Unit of Measure (UOM, e.g., SI.METER,
 * NonSI.FOOT) of each symbolizer. The resulting Style's Symbolizer sizes will
 * all be given in PIXELS, so that they can be directly used by a renderer that
 * is unaware of units of measure or the current map scale. For example, points
 * with size == 100 meters could be rescaled to 10 pixels for higher levels of
 * zoom and 2 pixels for a lower level of zoom.
 * <p>
 * This visitor extends {...@link DuplicatingStyleVisitor} and as such yields a
 * copy of the original Style. Usage is simply to call the desired visit()
 * method and then call getCopy() to retrieve the result.
 * 
 * @author milton
 */
public class UomRescaleStyleVisitor extends DuplicatingStyleVisitor
{
    private double _mapScale = 1;

    /**
     * Constructor: requires the current mapScale to inform the window to
     * viewport (world to screen) relation in order to correctly rescale sizes
     * according to units of measure given in world units (e.g., SI.METER,
     * NonSI.FOOT, etc).
     * 
     * @param mapScale The specified map scale, given in pixels per meter.
     */
    public UomRescaleStyleVisitor(double mapScale)
    {
        if (mapScale <= 0)
            throw new IllegalArgumentException("mapScale must be positive.");
        
        _mapScale = mapScale;
    }

    /**
     * Used to rescale the provided unscaled value.
     * 
     * @param unscaled the unscaled value.
     * @param mapScale the mapScale in pixel per meter.
     * @param uom the uom that will be used to scale.
     * @return expr multiplied by the provided scale
     */
    protected Expression rescale(Expression unscaled, double mapScale, Unit<Length> uom)
    {
        if (unscaled == null || unscaled.equals(Expression.NIL))
            return unscaled;

        double rescaled = rescale(unscaled.evaluate(null, Double.class), mapScale, uom);
        return ff.literal(rescaled);
    }

    /**
     * Used to rescale the provided unscaled value.
     * <p>
     * We do optimize the case where the provided expression is a literal; no
     * sense doing a calculation each time if we don't have to.
     * 
     * @param unscaled the unscaled value.
     * @param mapScale the mapScale in pixel per meter.
     * @param uom the uom that will be used to scale.
     * @return an scaled value.
     */
    protected double rescale(double unscaled, double mapScale, Unit<Length> uom)
    {
        // no scaling to do if UOM is PIXEL (or null, which stands for PIXEL as
        // well)
        if (uom == null || uom.equals(NonSI.PIXEL))
            return unscaled;

        // computes the scale value for meters given the mapScale
        double scaledMetersToPixel = unscaled * mapScale;

        // converts value from meters to given UOM
        UnitConverter converter = uom.getConverterTo(SI.METER);
        double rescaled = converter.convert(scaledMetersToPixel);

        // asserts that the value is at least 1 (pixel size < 1 is invalid)
        return Math.max(1, rescaled);
    }

    @Override
    public void visit(PointSymbolizer ps)
    {
        super.visit(ps);
        PointSymbolizer copy = (PointSymbolizer) pages.peek();

        Graphic copyGraphic = copy.getGraphic();
        copyGraphic.setSize(rescale(copyGraphic.getSize(), _mapScale, copy.getUnitOfMeasure()));
    }

    @Override
    public void visit(LineSymbolizer line)
    {
        super.visit(line);
        LineSymbolizer copy = (LineSymbolizer) pages.peek();

        Stroke copyStroke = copy.getStroke();
        copyStroke.setWidth(rescale(copyStroke.getWidth(), _mapScale, copy.getUnitOfMeasure()));
    }

    @Override
    public void visit(PolygonSymbolizer poly)
    {
        super.visit(poly);
        PolygonSymbolizer copy = (PolygonSymbolizer) pages.peek();

        Stroke copyStroke = copy.getStroke();
        copyStroke.setWidth(rescale(copyStroke.getWidth(), _mapScale, copy.getUnitOfMeasure()));
    }
}
------------------------------------------------------------------------------
Crystal Reports - New Free Runtime and 30 Day Trial
Check out the new simplified licensing option that enables unlimited
royalty-free distribution of the report engine for externally facing 
server and web deployment.
http://p.sf.net/sfu/businessobjects
_______________________________________________
Geotools-devel mailing list
Geotools-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/geotools-devel

Reply via email to