geotools学习(九)函数
2019-10-29 本文已影响0人
MrSwilder
函数教程
向GeoTools添加函数是扩展该库的非常有用的介绍。这通常用于在样式化时生成值,否则无法使用表达式完成。
捕捉函数
- 下面是一个快速实现从一个点捕捉到一行:
/*
* 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;
}
}
- 如果你感兴趣的话,可以在“Snap a Point to a Line”这一单元中学习使用LocationIndexLine的技巧。
- 需要注意的一点是,FunctionName的定义用于向新函数的用户描述有效的参数。
按照惯例,我们将其定义为一个静态的final SnapFunction。但是,这只是一个约定(它将有助于实现下一节)。 - 创建实现FunctionFactory的ExampleFunctionFactory
- 填写以下代码:
/*
* 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之前加载它。
- 我们现在可以通过在META-INF/services/下向jar添加一个文件来注册我们的工厂。
在你的jar中创建以下文件:
- src/main/resources/META-INF/services/org.geotools.filter.FunctionFactory
Maven将src/main/resources的内容收集到jar中,
- 填写以下内容(每行一个实现类):
org.geotools.tutorial.function.ExampleFunctionFactory
- 那就是SnapFunction现在发布了!
你可以从你的SLD文件中使用“snap”功能;或者在普通的java程序中。
扩展
- 创建一个快速测试用例,以显示上述功能是可用的使用:
FilterFactory ff = CommonFactoryFinder.getFilterFactory();
Expression expr = ff.function("snap", ff.property("the_geom"), ff.literal(lines));
-
该函数将非常缓慢写入(当调用捕捉数千点)。
检查一下你是否可以检测到文字的多重线性化;并在调用函数之间缓存LocationIndexedLine。许多地理工具功能都以这种方式进行了优化。 -
上面的代码中有相当一部分是“样板代码”,可以使用适当的AbstractFunction类进行简化。
GeoTools确实提供了两个抽象类,您可以在定义自己的函数时扩展它们。看看FunctionImpl,看看它是否比从头开始更容易。 -
函数用来处理它们的参数并产生一个答案:
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;
}
}