开源geotools

geotools学习(九)函数

2019-10-29  本文已影响0人  MrSwilder

函数教程

向GeoTools添加函数是扩展该库的非常有用的介绍。这通常用于在样式化时生成值,否则无法使用表达式完成。

捕捉函数

  1. 下面是一个快速实现从一个点捕捉到一行:
/*
 *    GeoTools - The Open Source Java GIS Toolkit
 *    http://geotools.org
 *
 *    (C) 2019, 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.tutorial.function;

import java.util.List;
import org.geotools.filter.capability.FunctionNameImpl;
import org.geotools.util.Converters;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.linearref.LinearLocation;
import org.locationtech.jts.linearref.LocationIndexedLine;
import org.opengis.filter.capability.FunctionName;
import org.opengis.filter.expression.Expression;
import org.opengis.filter.expression.ExpressionVisitor;
import org.opengis.filter.expression.Function;
import org.opengis.filter.expression.Literal;

/**
 * Quick function that illustrates snapping to a line.
 *
 * @author jody
 */
public class SnapFunction implements Function {

    static FunctionName NAME =
            new FunctionNameImpl(
                    "snap",
                    Point.class,
                    FunctionNameImpl.parameter("point", Point.class),
                    FunctionNameImpl.parameter("line", Geometry.class));

    private final List<Expression> parameters;

    private final Literal fallback;

    public SnapFunction(List<Expression> parameters, Literal fallback) {
        if (parameters == null) {
            throw new NullPointerException("parameters required");
        }
        if (parameters.size() != 2) {
            throw new IllegalArgumentException("snap( point, line) requires two parameters only");
        }
        this.parameters = parameters;
        this.fallback = fallback;
    }

    public Object evaluate(Object object) {
        return evaluate(object, Point.class);
    }

    public <T> T evaluate(Object object, Class<T> context) {
        Expression pointExpression = parameters.get(0);
        Point point = pointExpression.evaluate(object, Point.class);

        Expression lineExpression = parameters.get(1);
        Geometry line = lineExpression.evaluate(object, Geometry.class);

        LocationIndexedLine index = new LocationIndexedLine(line);

        LinearLocation location = index.project(point.getCoordinate());

        Coordinate snap = index.extractPoint(location);

        Point pt = point.getFactory().createPoint(snap);

        return Converters.convert(pt, context); // convert to requested format
    }

    public Object accept(ExpressionVisitor visitor, Object extraData) {
        return visitor.visit(this, extraData);
    }

    public String getName() {
        return NAME.getName();
    }

    public FunctionName getFunctionName() {
        return NAME;
    }

    public List<Expression> getParameters() {
        return parameters;
    }

    public Literal getFallbackValue() {
        return fallback;
    }
}
  1. 如果你感兴趣的话,可以在“Snap a Point to a Line”这一单元中学习使用LocationIndexLine的技巧。
  2. 需要注意的一点是,FunctionName的定义用于向新函数的用户描述有效的参数。
    按照惯例,我们将其定义为一个静态的final SnapFunction。但是,这只是一个约定(它将有助于实现下一节)。
  3. 创建实现FunctionFactory的ExampleFunctionFactory
  4. 填写以下代码:
/*
 *    GeoTools - The Open Source Java GIS Toolkit
 *    http://geotools.org
 *
 *    (C) 2019, 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.tutorial.function;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.geotools.feature.NameImpl;
import org.geotools.filter.FunctionFactory;
import org.opengis.feature.type.Name;
import org.opengis.filter.capability.FunctionName;
import org.opengis.filter.expression.Expression;
import org.opengis.filter.expression.Function;
import org.opengis.filter.expression.Literal;

public class ExampleFunctionFactory implements FunctionFactory {

    public List<FunctionName> getFunctionNames() {
        List<FunctionName> functionList = new ArrayList<>();
        functionList.add(SnapFunction.NAME);
        return Collections.unmodifiableList(functionList);
    }

    public Function function(String name, List<Expression> args, Literal fallback) {
        return function(new NameImpl(name), args, fallback);
    }

    public Function function(Name name, List<Expression> args, Literal fallback) {
        if (SnapFunction.NAME.getFunctionName().equals(name)) {
            return new SnapFunction(args, fallback);
        }
        return null; // we do not implement that function
    }
}

6.我们引用静态的final SnapFunction.NAME。
虽然我们提到这只是一个约定,但是您可以自由地创建一个新的FunctionNameImpl(“snap”、“point”、“line”)作为getFunctionNames()方法的一部分。这样做的好处是避免在用户按名称请求SnapFunction之前加载它。

  1. 我们现在可以通过在META-INF/services/下向jar添加一个文件来注册我们的工厂。
    在你的jar中创建以下文件:
  1. 填写以下内容(每行一个实现类):
org.geotools.tutorial.function.ExampleFunctionFactory
  1. 那就是SnapFunction现在发布了!
    你可以从你的SLD文件中使用“snap”功能;或者在普通的java程序中。

扩展

FilterFactory ff = CommonFactoryFinder.getFilterFactory();
Expression expr = ff.function("snap", ff.property("the_geom"), ff.literal(lines));
public Object evaluate(Object feature) {
    Expression geomExpression = parameters.get(0);
    Geometry geom = geomExpression.evaulate(feature, Geometry.class);

    return geom.centroid();
}

当一个函数作为样式的一部分使用时,用户通常希望根据所绘制的特性的属性计算一个值。表达式PropertyName以这种方式用于从特性中提取值并将其传递到函数中进行计算
重要提示:当我们以一种风格使用您的功能时,我们会尽量提高效率。如果样式在没有引用PropertyName的情况下调用函数,那么它将只被调用一次。假设每次调用该函数时都会产生相同的值,因此对于所有特性都会产生相同的值。通过只调用一次函数(并记住结果),呈现引擎可以执行得更快。
如果这不是你想要的功能,请实现如下功能:

public class MagicFunction extends FunctionExpressionImpl implements VolatileFunction {
    Random random;
    public MagicFunction() {
        super("magic");
        random = new Random();
    }
    public int getArgCount() {
        return 0; // no arguments!
    }
    public Object evaluate(Object feature) {
        float r = rand.nextFloat();
        float g = rand.nextFloat();
        float b = rand.nextFloat();

        Color color = new Color(r, g, b);

        return color;
    }
}
上一篇下一篇

猜你喜欢

热点阅读