Package org.geotools.styling.visitor

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

/*
*    GeoTools - The Open Source Java GIS Toolkit
*    http://geotools.org
*
*    (C) 2007-2008, 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 static org.geotools.styling.TextSymbolizer.*;

import java.util.Map;

import javax.measure.quantity.Length;
import javax.measure.unit.Unit;

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.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.RasterSymbolizer;
import org.geotools.styling.Stroke;
import org.geotools.styling.Symbol;
import org.geotools.styling.Symbolizer;
import org.geotools.styling.TextSymbolizer;
import org.geotools.util.Converters;
import org.opengis.filter.FilterFactory2;
import org.opengis.filter.expression.Expression;
import org.opengis.filter.expression.Literal;

/**
* This is a style visitor that will produce a copy of the provided
* style rescaled by a provided factor.
* <p>
* The provided scale will be use to modify all line widths, font sizes and
* so forth. We may need to go the extra distance and play with the min/max
* scale on rules, and if there is any DPI specific madness going on we are
* going to cry.
* <p>
* According to the specification we are supposed to use environmental variables
* to make our styles render in a resolution independent manner. The current
* GeoTools environment variable visitor only does processing for <b>mapscale</b>
* but does not have a dpi substitution. On the plus side this visitor accepts
* a general Expression and you are free to use an environmental variable expression
* in order to make sure a normal base style is tweaked in all the right spots.
* <p>
*
* @author Jody Garnett (Refractions Research)
*
*
*
* @source $URL$
*/
public class RescaleStyleVisitor extends DuplicatingStyleVisitor {
   
    /**
     * This is the scale used as a multiplication factory for everything that
     * has a size.
     */
    protected Expression scale;
   
    protected Unit<Length> defaultUnit;

    public RescaleStyleVisitor( double scale ){
        this( CommonFactoryFinder.getFilterFactory2(null), scale );
    }
   
    public RescaleStyleVisitor( Expression scale){
        this( CommonFactoryFinder.getFilterFactory2(null), scale );
    }
   
    public RescaleStyleVisitor(FilterFactory2 filterFactory, double scale) {
        this( filterFactory, filterFactory.literal(scale));
    }

    public RescaleStyleVisitor(FilterFactory2 filterFactory, Expression scale) {
        super( CommonFactoryFinder.getStyleFactory( null ), filterFactory );
        this.scale = scale;
    }
    /**
     * Used to rescale the provided expr.
     * <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 expr
     * @return expr multiplied by the provided scale
     */
    protected Expression rescale( Expression expr ) {
        if(expr == null) {
            return null;
        }
        if(expr == Expression.NIL) {
            return Expression.NIL;
        }
       
        Measure m = new Measure(expr, defaultUnit);
        return RescalingMode.KeepUnits.rescaleToExpression(scale, m);
    }

    /**
     * Increase stroke width.
     * <p>
     * Based on feedback we may need to change the dash array as well.
     * <p>
     */
    public void visit(org.geotools.styling.Stroke stroke) {
        Stroke copy = sf.getDefaultStroke();
        copy.setColor( copy(stroke.getColor()));
        copy.setDashArray( rescale(stroke.getDashArray()));
        copy.setDashOffset( rescale(stroke.getDashOffset()));
        copy.setGraphicFill( copy(stroke.getGraphicFill()));
        copy.setGraphicStroke( copy( stroke.getGraphicStroke()));
        copy.setLineCap(copy(stroke.getLineCap()));
        copy.setLineJoin( copy(stroke.getLineJoin()));
        copy.setOpacity( copy(stroke.getOpacity()));
        copy.setWidth( rescale(stroke.getWidth()));
        pages.push(copy);
    }  
   
    float[] rescale(float[] original) {
        if(original == null) {
            return null;
        }
       
        // rescale the dash array if possible
        float[] rescaled = new float[original.length];
        float scaleFactor = 1;
        if( scale instanceof Literal){
            scaleFactor = scale.evaluate(null, Float.class);
        }
        for (int i = 0; i < rescaled.length; i++) {
            rescaled[i] = scaleFactor * original[i];
        }
       
        return rescaled;
    }

    /** Make graphics (such as used with PointSymbolizer) bigger */
    public void visit(Graphic gr) {
        Graphic copy = null;

        Displacement displacementCopy = null;

        if (gr.getDisplacement() != null) {
            gr.getDisplacement().accept(this);
            displacementCopy = (Displacement) pages.pop();
        }

        ExternalGraphic[] externalGraphics = gr.getExternalGraphics();
        ExternalGraphic[] externalGraphicsCopy = new ExternalGraphic[externalGraphics.length];

        int length=externalGraphics.length;
        for (int i = 0; i < length; i++) {
            externalGraphicsCopy[i] = copy( externalGraphics[i]);
        }

        Mark[] marks = gr.getMarks();
        Mark[] marksCopy = new Mark[marks.length];
        length=marks.length;
        for (int i = 0; i < length; i++) {
            marksCopy[i] = copy( marks[i]);
        }

        Expression opacityCopy = copy( gr.getOpacity() );
        Expression rotationCopy = copy( gr.getRotation() );
        Expression sizeCopy = rescaleGraphicSize(gr);
       
        Symbol[] symbols = gr.getSymbols();
        length=symbols.length;
        Symbol[] symbolCopys = new Symbol[length];

        for (int i = 0; i < length; i++) {
            symbolCopys[i] = copy( symbols[i] );
        }

        copy = sf.createDefaultGraphic();
        copy.setDisplacement(displacementCopy);
        copy.setExternalGraphics(externalGraphicsCopy);
        copy.setMarks(marksCopy);
        copy.setOpacity((Expression) opacityCopy);
        copy.setRotation((Expression) rotationCopy);
        copy.setSize((Expression) sizeCopy);
        copy.setSymbols(symbolCopys);

        pages.push(copy);
    }
   
    protected Expression rescaleGraphicSize(Graphic gr) {
        return rescale(gr.getSize());
    }

    @Override
    public void visit(TextSymbolizer text) {
        this.defaultUnit = text.getUnitOfMeasure();
        try {
            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);
            rescaleArrayOption(options, GRAPHIC_MARGIN_KEY, 0);
        } finally {
            this.defaultUnit = null;
        }    
    }
   
    @Override   
    public void visit(Symbolizer sym) {
        this.defaultUnit = sym.getUnitOfMeasure();
        try {
            super.visit(sym);
        } finally {
            this.defaultUnit = null;
        }       
    }
   
    @Override   
    public void visit(PointSymbolizer sym) {
        this.defaultUnit = sym.getUnitOfMeasure();
        try {
            super.visit(sym);
        } finally {
            this.defaultUnit = null;
        }       
    }
   
    @Override   
    public void visit(LineSymbolizer sym) {
        this.defaultUnit = sym.getUnitOfMeasure();
        try {
            super.visit(sym);
        } finally {
            this.defaultUnit = null;
        }       
    }
   
    @Override   
    public void visit(PolygonSymbolizer sym) {
        this.defaultUnit = sym.getUnitOfMeasure();
        try {
            super.visit(sym);
        } finally {
            this.defaultUnit = null;
        }       
    }
   
    @Override   
    public void visit(RasterSymbolizer sym) {
        this.defaultUnit = sym.getUnitOfMeasure();
        try {
            super.visit(sym);
        } finally {
            this.defaultUnit = null;
        }       
    }
   
    /**
     * 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)));
        }
       
    };
   
    /**
     * Rescales the specified vendor option
     * @param options
     * @param key
     * @param defaultAutoWrap
     * @param value
     */
    protected void rescaleArrayOption(Map<String, String> options, String key, int defaultValue) {
        double scaleFactor = (double) scale.evaluate(null, Double.class);
        if(options.get(key) != null) {
            String strValue = options.get(key);
            String[] splitted = strValue.split("\\s+");
            StringBuilder sb = new StringBuilder();
            for (String value : splitted) {
                double rescaled = (int) Math.round(Double.parseDouble(value) * scaleFactor);
                sb.append((int) rescaled).append(" ");
            }
            sb.setLength(sb.length() - 1);
            options.put(key, sb.toString());
        } else if(defaultValue != 0) {
            options.put(key, String.valueOf((int) Math.round(defaultValue * scaleFactor)));
        }
       
    };
   
}
TOP

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

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.