如何将 Geotools 中的 PropertyName 用于用户定义的函数?

How to utilize PropertyName in Geotools for a user-defined function?

我正在尝试使用 geotools.org library (Version 24) to write a user-defined function to style my GIS map according to an external data source. The documentation for the GeoTools library includes this tantalizing paragraph in the section on Functions:

When a function is used as part of a Style users often want to calculate a value based on the attributes of the Feature being drawn. The Expression PropertyName is used in this fashion to extract values out of a Feature and pass them into the function for evaluation.

这正是我想要做的。但是,该文档没有关于如何执行此操作的实际示例

我花了好几天时间尝试对函数定义进行各种排列,每次都得到相同的结果:我的用户定义函数只接收几何属性,而不是我指定的额外属性。

我已验证其他一切正常:

  1. 从 shapefile 中正确读取特征
  2. 实际调用函数
  3. 要素几何被传递到函数中
  4. 完成后绘制地图

但我无法让 Geotools 库从 shapefile 中传递额外的要素属性。有没有人得到这个工作,或者你能给我指出一个使用它的例子吗?

我当前的函数定义:

package org.geotools.tutorial.function;

import mycode.data.dao.MyTableDao;
import mycode.data.model.MyTable;
import org.geotools.filter.FunctionExpressionImpl;
import org.geotools.filter.capability.FunctionNameImpl;
import org.opengis.feature.Feature;
import org.opengis.filter.capability.FunctionName;
import org.opengis.filter.expression.PropertyName;
import org.opengis.filter.expression.VolatileFunction;
import org.springframework.beans.factory.annotation.Autowired;

import java.awt.*;
import java.beans.Expression;
import java.util.Random;

public class DataFunction extends FunctionExpressionImpl  {

    @Autowired
    MyTableDao myTableDao;

    public static FunctionName NAME =
            new FunctionNameImpl(
                    "DataFunction",
                    Color.class,
                    FunctionNameImpl.parameter("featureData1", PropertyName.class),
                    FunctionNameImpl.parameter("featureData2", PropertyName.class));

    public DataFunction() {
        super("DataFunction");
    }

    public int getArgCount() {
        return 2;
    }

    @Override
    public Object evaluate(Object feature) {
        Feature f = (Feature) feature;

        // fallback definition
        float pct = 0.5F;

        if (f.getProperty("featureData1") != null) {
            MyTable temp = myTableDao.read(
                    f.getProperty("featureData1").getValue().toString(),
                    f.getProperty("featureData2").getValue().toString());

            pct = temp.getColumnValue();
        }

        Color color = new Color(pct, pct, pct);

        return color;
    }
}

编辑:我通过在代码中创建的样式以编程方式调用函数。然后将此样式添加到图层,图层在绘制过程中添加到地图。

private Style createMagicStyle(File file, FeatureSource featureSource) {

    FeatureType schema = (FeatureType) featureSource.getSchema();

    // create a partially opaque outline stroke
    Stroke stroke =
            styleFactory.createStroke(
                    filterFactory.literal(Color.BLUE),
                    filterFactory.literal(1),
                    filterFactory.literal(0.5));

    // create a partial opaque fill
    Fill fill =
            styleFactory.createFill(
                    filterFactory.function("DataFunction",
                            new AttributeExpressionImpl("featureData1"),
                            new AttributeExpressionImpl("featureData2")));

    /*
     * Setting the geometryPropertyName arg to null signals that we want to
     * draw the default geomettry of features
     */
    PolygonSymbolizer sym = styleFactory.createPolygonSymbolizer(stroke, fill, null);

    Rule rule = styleFactory.createRule();
    rule.symbolizers().add(sym);
    FeatureTypeStyle fts = styleFactory.createFeatureTypeStyle(new Rule[] {rule});
    Style style = styleFactory.createStyle();
    style.featureTypeStyles().add(fts);

    return style;
}

我想你想设置你的函数来接受一对字符串或双打(或任何这些属性),比如:

public static FunctionName NAME =
        new FunctionNameImpl(
                "DataFunction",
                Color.class,
                FunctionNameImpl.parameter("featureData1", Double.class),
                FunctionNameImpl.parameter("featureData2", Double.class));

 public DataFunction(List<Expression> params, Literal fallback) {
     this.params = params;
     this.fallback = fallback;
 }

那么您的 evaluate 方法将变为:

@Override
public Object evaluate(Object feature) {
    Feature f = (Feature) feature;

    // fallback definition
    float pct = 0.5F;
    Expression exp1 = params.get(0);
    Expression exp2 = params.get(1);
    if (f.getProperty("featureData1") != null) {
        MyTable temp = myTableDao.read(
                exp1.evaluate(f, Double.class),
                exp2.evaluate(f, Double.class));

        pct = temp.getColumnValue();
    }

    Color color = new Color(pct, pct, pct);

    return color;
}

您可以使用类似以下的样式来使用它:

Fill fill =
        styleFactory.createFill(
                filterFactory.function("DataFunction",
                        filterFactory.propertyName("featureData1"),
                        filterFactory.propertyName("featureData2")));