Package org.geotools.styling.visitor

Source Code of org.geotools.styling.visitor.UomRescaleStyleVisitor

/*
*    GeoTools - The Open Source Java GIS Toolkit
*    http://geotools.org
*
*    (C) 2002-2013, Open Source Geospatial Foundation (OSGeo)
*
*    This library is free software; you can redistribute it and/or
*    modify it under the terms of the GNU Lesser General Public
*    License as published by the Free Software Foundation;
*    version 2.1 of the License.
*
*    This library is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
*    Lesser General Public License for more details.
*/
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 org.geotools.styling.Displacement;
import org.geotools.styling.Fill;
import org.geotools.styling.Font;
import org.geotools.styling.Graphic;
import org.geotools.styling.LabelPlacement;
import org.geotools.styling.LinePlacement;
import org.geotools.styling.LineSymbolizer;
import org.geotools.styling.Mark;
import org.geotools.styling.PointPlacement;
import org.geotools.styling.PointSymbolizer;
import org.geotools.styling.PolygonSymbolizer;
import org.geotools.styling.Stroke;
import org.geotools.styling.TextSymbolizer;
import org.geotools.styling.TextSymbolizer2;
import org.opengis.filter.expression.Expression;
import org.opengis.style.GraphicalSymbol;

/**
* 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
* @author Andrea Aime - GeoSolutions
*
*
* @source $URL$
*/
public class UomRescaleStyleVisitor extends DuplicatingStyleVisitor {

    double mapScale;

    /**
     * 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("The mapScale is out of range. Value is "
                    + Double.toString(mapScale) + ". It must be positive.");

        this.mapScale = mapScale;
    }

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

        Measure m = new Measure(unscaled, uom);
        return RescalingMode.RealWorld.rescaleToExpression(ff.literal(mapScale), m);
    }

    /**
     * Used to rescale the provided unscaled value.
     *
     * @param unscaled the unscaled value.
     * @param mapScale the mapScale in pixels per meter.
     * @param uom the unit of measure that will be used to scale.
     * @return the expression multiplied by the provided scale.
     */
    protected String rescale(String unscaled, Unit<Length> uom) {
        if (unscaled == null) {
            return unscaled;
        }

        Measure v = new Measure(unscaled, uom);
        return RescalingMode.RealWorld.rescaleToString(mapScale, v);
    }

    /**
     * Used to rescale the provided dash array.
     *
     * @param dashArray the unscaled dash array. If null, the method returns null.
     * @param mapScale the mapScale in pixels per meter.
     * @param uom the unit of measure that will be used to scale.
     * @return the rescaled dash array
     */
    protected float[] rescale(float[] dashArray, Unit<Length> unitOfMeasure) {
        if (dashArray == null)
            return null;
        if (unitOfMeasure == null || unitOfMeasure.equals(NonSI.PIXEL))
            return dashArray;

        float[] rescaledDashArray = new float[dashArray.length];

        for (int i = 0; i < rescaledDashArray.length; i++) {
            rescaledDashArray[i] = Float.parseFloat(rescale(String.valueOf(dashArray[i]), unitOfMeasure));
        }
        return rescaledDashArray;
    }

    /**
     * Used to rescale the provided stroke.
     *
     * @param stroke the unscaled stroke, which will be modified in-place.
     * @param mapScale the mapScale in pixels per meter.
     * @param uom the unit of measure that will be used to scale.
     */
    protected void rescaleStroke(Stroke stroke, Unit<Length> uom) {
        if (stroke != null) {
            stroke.setWidth(rescale(stroke.getWidth(), uom));
            stroke.setDashArray(rescale(stroke.getDashArray(), uom));
            stroke.setDashOffset(rescale(stroke.getDashOffset(), uom));
            rescale(stroke.getGraphicFill(), uom);
            rescale(stroke.getGraphicStroke(), uom);
        }
    }

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

        Unit<Length> uom = copy.getUnitOfMeasure();
        Graphic copyGraphic = copy.getGraphic();
        rescale(copyGraphic, uom);
        copy.setUnitOfMeasure(NonSI.PIXEL);
    }

    private void rescale(Graphic graphic, Unit<Length> unit) {
        if (graphic != null) {
            graphic.setSize(rescale(graphic.getSize(), unit));
            graphic.setGap(rescale(graphic.getGap(), unit));

            Displacement disp = graphic.getDisplacement();
            if (disp != null) {
                disp.setDisplacementX(rescale(disp.getDisplacementX(), unit));
                disp.setDisplacementY(rescale(disp.getDisplacementY(), unit));
                graphic.setDisplacement(disp);
            }

            if (graphic.graphicalSymbols() != null) {
                for (GraphicalSymbol gs : graphic.graphicalSymbols()) {
                    if (gs instanceof Mark) {
                        Mark mark = (Mark) gs;
                        rescaleStroke(mark.getStroke(), unit);
                        rescaleFill(mark.getFill(), unit);
                    }
                }
            }
        }
    }

    @Override
    public void visit(LineSymbolizer line) {
        super.visit(line);
        LineSymbolizer copy = (LineSymbolizer) pages.peek();
        Unit<Length> uom = copy.getUnitOfMeasure();
        Stroke copyStroke = copy.getStroke();
        rescaleStroke(copyStroke, uom);
        copy.setUnitOfMeasure(NonSI.PIXEL);
    }

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

        Unit<Length> uom = copy.getUnitOfMeasure();
        rescaleStroke(copy.getStroke(), uom);
        rescaleFill(copy.getFill(), uom);
        copy.setUnitOfMeasure(NonSI.PIXEL);
    }

    private void rescaleFill(Fill copyFill, Unit<Length> unit) {
        // rescale the graphic fill, if any
        if (copyFill != null) {
            rescale(copyFill.getGraphicFill(), unit);
        }
    }

    @SuppressWarnings("deprecation")
    @Override
    public void visit(TextSymbolizer text) {
        super.visit(text);
        TextSymbolizer copy = (TextSymbolizer) pages.peek();

        Unit<Length> uom = copy.getUnitOfMeasure();
        // rescales fonts
        Font[] fonts = copy.getFonts();
        for (Font font : fonts)
            font.setSize(rescale(font.getSize(), uom));
        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(), uom));
                disp.setDisplacementY(rescale(disp.getDisplacementY(), uom));
                pointPlacement.setDisplacement(disp);
            }
        } else if (placement instanceof LinePlacement) {
            // rescales line label placement
            LinePlacement linePlacement = (LinePlacement) placement;
            linePlacement.setGap(rescale(linePlacement.getGap(), uom));
            linePlacement.setInitialGap(rescale(linePlacement.getInitialGap(), uom));
            linePlacement.setPerpendicularOffset(rescale(linePlacement.getPerpendicularOffset(),
                    uom));
        }
        copy.setLabelPlacement(placement);

        // rescale the halo
        if (copy.getHalo() != null) {
            copy.getHalo().setRadius(rescale(copy.getHalo().getRadius(), uom));
        }

        if (copy instanceof TextSymbolizer2) {
            TextSymbolizer2 copy2 = (TextSymbolizer2) copy;

            rescale(copy2.getGraphic(), uom);
        }

        // scale various options as well
        Map<String, String> options = copy.getOptions();
        scaleIntOption(options, TextSymbolizer.MAX_DISPLACEMENT_KEY, uom);
        scaleIntOption(options, TextSymbolizer.SPACE_AROUND_KEY, uom);
        scaleIntOption(options, TextSymbolizer.MIN_GROUP_DISTANCE_KEY, uom);
        scaleIntOption(options, TextSymbolizer.LABEL_REPEAT_KEY, uom);
        scaleIntOption(options, TextSymbolizer.AUTO_WRAP_KEY, uom);
        scaleIntArrayOption(options, TextSymbolizer.GRAPHIC_MARGIN_KEY, uom);

        copy.setUnitOfMeasure(NonSI.PIXEL);
    }

    private void scaleIntOption(Map<String, String> options, String optionName, Unit<Length> uom) {
        if (options.containsKey(optionName)) {
            String rescaled = rescale(options.get(optionName), uom);

            options.put(optionName, toInt(rescaled));
        }
    }

    private void scaleIntArrayOption(Map<String, String> options, String optionName,
            Unit<Length> uom) {
        if (options.containsKey(optionName)) {
            String strValue = options.get(optionName);
            String[] splitted = strValue.split("\\s+");
            StringBuilder sb = new StringBuilder();
            for (String value : splitted) {
                String rescaled = rescale(value, uom);
                sb.append(toInt(rescaled)).append(" ");
            }
            sb.setLength(sb.length() - 1);
            options.put(optionName, sb.toString());
        }
    }
   
    String toInt(String value) {
        Double dv = Double.valueOf(value);
        return String.valueOf(dv.intValue());
    }
}
TOP

Related Classes of org.geotools.styling.visitor.UomRescaleStyleVisitor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.