/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2013-2016, 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 javax.measure.quantity.Length; import javax.measure.unit.NonSI; import javax.measure.unit.SI; import javax.measure.unit.Unit; import org.geotools.factory.CommonFactoryFinder; import org.geotools.filter.visitor.SimplifyingFilterVisitor; import org.geotools.util.Converters; import org.opengis.filter.Filter; import org.opengis.filter.FilterFactory; import org.opengis.filter.PropertyIsNull; import org.opengis.filter.expression.Expression; import org.opengis.filter.expression.Literal; import org.opengis.filter.expression.NilExpression; /** * Helper class that parses a measure with eventual local unit of measure and helps the * {@link RescalingMode} enumeration to perfom its scaling job * * @author Andrea Aime - GeoSolutions * */ class Measure { static final FilterFactory ff = CommonFactoryFinder.getFilterFactory(); Expression expression; Double value; Unit<Length> uom; Unit<Length> defaultUnit; public Measure(String value, Unit<Length> defaultUnit) { setDefaultUnit(defaultUnit); processLiteralExpression(value, defaultUnit); } public Measure(Expression unscaled, Unit<Length> defaultUnit) { this.expression = unscaled; setDefaultUnit(defaultUnit); this.uom = defaultUnit; if (unscaled instanceof Literal) { processLiteralExpression((Literal) unscaled, defaultUnit); } else { // see if we can still optimize PropertyIsNull test = ff.isNull(unscaled); Filter simplified = (Filter) test.accept(new SimplifyingFilterVisitor(), null); if (simplified == Filter.INCLUDE) { // special case, the expression was nil to start with this.expression = NilExpression.NIL; this.uom = defaultUnit; } else if (simplified instanceof PropertyIsNull) { PropertyIsNull pin = (PropertyIsNull) simplified; Expression se = pin.getExpression(); if (se instanceof Literal) { processLiteralExpression((Literal) se, defaultUnit); } else { this.expression = se; this.uom = defaultUnit; } } } } private void setDefaultUnit(Unit<Length> defaultUnit) { if (defaultUnit == null) { this.defaultUnit = NonSI.PIXEL; } else { this.defaultUnit = defaultUnit; } } private void processLiteralExpression(Literal literal, Unit<Length> defaultUnit) { // check if we have a uom attached at the end of the expression String value = literal.evaluate(null, String.class); if (value == null) { // let it go without doing anything, it may be a ConstantExpression.NULL return; } processLiteralExpression(value, defaultUnit); } private void processLiteralExpression(String value, Unit<Length> defaultUnit) { Unit<Length> uom = defaultUnit; String unitless = value; if (value.endsWith("px")) { unitless = value.substring(0, value.length() - 2); uom = NonSI.PIXEL; } else if (value.endsWith("ft")) { unitless = value.substring(0, value.length() - 2); uom = NonSI.FOOT; } else if (value.endsWith("m")) { unitless = value.substring(0, value.length() - 1); uom = SI.METER; } Double measure = Converters.convert(unitless, Double.class); if (measure == null) { throw new IllegalArgumentException("Invalid measure '" + value + "', was expecting a number, eventually followed by px, m or ft"); } this.expression = ff.literal(value); this.value = measure; this.uom = uom; } /** * Returns true if the uom is set and is not pixel * * @return */ boolean isRealWorldUnit() { return uom != null && uom != NonSI.PIXEL; } /** * Returns true if the uom is pixel within a symbolizer whose default unit is also pixel * * @param measure * @return */ boolean isPixelInPixelDefault() { return (uom == null || uom == defaultUnit) && (defaultUnit == null || defaultUnit == NonSI.PIXEL); } /** * @return true, if the uom is a real world unit within a symbolizer whose default unit is pixel. */ public boolean isRealWorldUnitInPixelDefault() { return isRealWorldUnit() && (defaultUnit == null || defaultUnit == NonSI.PIXEL); } }