You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GeoTools内缓冲区质心图层属性导出问题及代码报错求助

基于GeoTools内缓冲区质心计算的导出属性问题及错误解决

我基于GeoTools实现了一个方法,通过内缓冲区计算多边形质心并生成点图层添加到地图。生成的点图层能在地图上正常显示,但导出时没有任何属性,需要至少将质心的坐标保存到属性表中。

第一次尝试的代码

/*
 * Erstellung eines Inneren Puffers mit anschließenden Schwerpunkt für einen
 * ausgewählten Layer. Diese Daten sind aus etlichen Internetforum
 * zusammengebaut. die Methode hat leider, so vermute ich es, probleme mit
 * bestimmten geometrien und somit entstehen Lücken in der Berechnung Variante 1
 */
public void InnerBufferCentroid() throws Exception {

    JLabel label = new JLabel("Wählen Sie einen Layer aus:");
    List<Layer> layerList = map.layers();
    String[] layerNames = new String[layerList.size()];
    for (int i = 0; i < layerList.size(); i++) {
        layerNames[i] = layerList.get(i).getFeatureSource().getName().toString();
    }
    String selectedLayer = (String) JOptionPane.showInputDialog(null, label, "Layerauswahl",
            JOptionPane.QUESTION_MESSAGE, null, layerNames, layerNames[0]);

    FeatureLayer selectedFeatureLayer = null;
    for (Layer layer : layerList) {
        if (layer.getFeatureSource().getName().toString().equals(selectedLayer)) {
            selectedFeatureLayer = (FeatureLayer) layer;
            break;
        }
    }
    System.out.println("Layerauswahl abgeschlossen");
    SimpleFeatureSource featureSource = (SimpleFeatureSource) selectedFeatureLayer.getFeatureSource();
    SimpleFeatureCollection featureCollection = featureSource.getFeatures();
    SimpleFeatureIterator featureIterator = featureCollection.features();

    // Erzeuge eine Liste aus den berechneten Zentroiden
    List<Point> centroidList = new ArrayList<Point>();

    // Berechne für jedes Polygon im Layer den Zentroid
    int featureCount = featureCollection.size();
    int currentFeature = 0;
    while (featureIterator.hasNext()) {
        System.out.println("Verarbeite Feature " + currentFeature + " von " + featureCount);

        currentFeature++;

        SimpleFeature feature = featureIterator.next();
        // Überprüfung des Arbeitsfortschrittes
        System.out.println("Processing feature with ID: " + feature.getID());
        Geometry geometry = (Geometry) feature.getDefaultGeometry();

        double originalArea = geometry.getArea();
        double bufferArea = originalArea;
        Geometry buffer = geometry.buffer(0);
        while (bufferArea >= originalArea * 0.05 && bufferArea > 0) {
            buffer = buffer.buffer(-500);// aus Performancegründe habe ich mich für 500m Schritte entschieden. Bei
                                            // der Größe werden noch für jeden Polygon Zentroide gerechnet, aber die
                                            // Berechnung dauert nicht zu lange
            bufferArea = buffer.getArea();
        }

        Point centr;
        if (buffer instanceof Polygon) {
            centr = ((Polygon) buffer).getInteriorPoint();
        } else {
            MultiPolygon multiPolygon = (MultiPolygon) buffer;
            int numGeometries = multiPolygon.getNumGeometries();
            Polygon largestPolygon = null;

            double largestArea = 0;
            for (int i = 0; i < numGeometries; i++) {
                Polygon polygon = (Polygon) multiPolygon.getGeometryN(i);
                double area = polygon.getArea();
                if (area > largestArea) {
                    largestArea = area;
                    largestPolygon = polygon;
                }
            }
            centr = largestPolygon.getCentroid();
        }
        centroidList.add(centr);
    }
    System.out.println("Zentroide berechnet");

    // Erzeuge ein Feature Collection aus den berechneten Zentroiden
    SimpleFeatureTypeBuilder featureTypeBuilder = new SimpleFeatureTypeBuilder();
    featureTypeBuilder.setName("Centroids");
    featureTypeBuilder.setCRS(CRS.decode("EPSG:25832"));
    featureTypeBuilder.add("centroid", Point.class);
    SimpleFeatureType featureType = featureTypeBuilder.buildFeatureType();
    SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(featureType);
    SimpleFeatureCollection centroidFeatureCollection = new DefaultFeatureCollection();
    for (Point centroid : centroidList) {
        featureBuilder.add(centroid);
        SimpleFeature centroidFeature = featureBuilder.buildFeature(null);
        ((DefaultFeatureCollection) centroidFeatureCollection).add(centroidFeature);
    }
    System.out.println(centroidFeatureCollection.size());
    // Erzeuge einen Layer aus den Zentroiden
    DefaultFeatureCollection defaultFeatureCollection = new DefaultFeatureCollection(null, featureType);
    defaultFeatureCollection.addAll(centroidFeatureCollection);
    FeatureSource featureS = new CollectionFeatureSource(defaultFeatureCollection);
//          Style style = SLD.createPointStyle("Centroid", Color.RED, Color.RED, 0.5f, 5);
    Style style = SLD.createSimpleStyle(featureType);
    Layer centroidLayer = new FeatureLayer(featureS, style);
    System.out.println("zur karte hinzufügen");

    // Füge den Layer dem Map Content hinzu
    map.addLayer(centroidLayer);
    System.out.println(map.layers());
}

这次尝试的问题是:未传递任何属性,导致导出的几何数据为空。之后我做了如下修改:

修改后的代码片段

// Erzeuge eine Liste aus den Attributen für die Punkte
List<AttributeDescriptor> attributes = new ArrayList<AttributeDescriptor>();
SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
builder.setName("Centroids");
builder.setCRS(CRS.decode("EPSG:25832"));
GeometryType geometryType = DataUtilities.createType("centroid", Point.class, CRS.decode("EPSG:25832"));
builder.add(geometryType);

// Erstelle die Feature-Typ-Definition
SimpleFeatureType featureType = builder.buildFeatureType();
// Erstelle die Feature-Collection
DefaultFeatureCollection featureCollection = new DefaultFeatureCollection("internal", featureType);

// Erstelle eine SimpleFeatureBuilder-Instanz zum Erstellen von Feature-Objekten
SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(featureType);

// Iteriere über den centroidList und erstelle für jeden Punkt ein Feature-Objekt
for (Point centroid : centroidList) {
    // Setze den Wert für das Attribut "centroid" im Feature-Objekt
    featureBuilder.set("centroid", centroid);

    // Erstelle das SimpleFeature-Objekt
    SimpleFeature feature = featureBuilder.buildFeature(null);

    // Füge das Feature der Feature-Collection hinzu
    featureCollection.addFeature(feature);
}

// Füge die Feature-Collection dem Layer hinzu
FeatureLayer centroidLayer = new FeatureLayer(featureCollection, style);

// Füge den Layer dem Map Content hinzu
map.addLayer(centroidLayer);

但修改后遇到两个错误:

  • 错误1:The method addFeature(SimpleFeature) is undefined for the type DefaultFeatureCollection.
  • 错误2:The method createType(String, String, String) in the type DataUtilities is not applicable for the arguments (String, Class<Point>, CoordinateReferenceSystem)

错误解决及属性添加方案

1. 解决错误2:DataUtilities.createType参数错误

DataUtilities.createType的正确用法是通过字符串定义几何类型,而非直接传入Class<Point>和CRS。你可以直接用SimpleFeatureTypeBuilder.add方法来添加几何属性,无需借助DataUtilities,代码更简洁:

SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
builder.setName("Centroids");
builder.setCRS(CRS.decode("EPSG:25832"));
// 直接添加几何属性,指定名称、类型和CRS
builder.add("centroid", Point.class, CRS.decode("EPSG:25832"));

如果一定要用DataUtilities,则需要按格式传入字符串:

GeometryType geometryType = (GeometryType) DataUtilities.createType("centroid:Point:srid=25832");

2. 解决错误1:DefaultFeatureCollection方法名错误

DefaultFeatureCollection添加要素的方法是add(SimpleFeature),而非addFeature,所以把featureCollection.addFeature(feature)改成:

featureCollection.add(feature);

3. 添加坐标属性到属性表

要解决导出无属性的问题,需要在SimpleFeatureType中添加x、y坐标字段,并在创建Feature时赋值:

// 创建FeatureType时添加坐标属性
SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
builder.setName("Centroids");
CoordinateReferenceSystem crs = CRS.decode("EPSG:25832");
builder.setCRS(crs);
builder.add("centroid", Point.class, crs);
// 添加x、y坐标属性
builder.add("x", Double.class);
builder.add("y", Double.class);
SimpleFeatureType featureType = builder.buildFeatureType();

// 创建Feature时赋值坐标
SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(featureType);
for (Point centroid : centroidList) {
    featureBuilder.set("centroid", centroid);
    // 获取质心坐标并赋值
    featureBuilder.set("x", centroid.getX());
    featureBuilder.set("y", centroid.getY());
    SimpleFeature feature = featureBuilder.buildFeature(null);
    featureCollection.add(feature);
}

完整修正后的核心代码片段

// 替换原代码中创建FeatureCollection及后续的部分
System.out.println("Zentroide berechnet");

// 创建带坐标属性的FeatureType
SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
builder.setName("Centroids");
CoordinateReferenceSystem crs = CRS.decode("EPSG:25832");
builder.setCRS(crs);
builder.add("centroid", Point.class, crs);
builder.add("x", Double.class);
builder.add("y", Double.class);
SimpleFeatureType featureType = builder.buildFeatureType();

// 创建FeatureCollection
DefaultFeatureCollection featureCollection = new DefaultFeatureCollection("internal", featureType);
SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(featureType);

// 生成带属性的Feature
for (Point centroid : centroidList) {
    featureBuilder.set("centroid", centroid);
    featureBuilder.set("x", centroid.getX());
    featureBuilder.set("y", centroid.getY());
    SimpleFeature feature = featureBuilder.buildFeature(null);
    featureCollection.add(feature);
}

// 创建图层并添加到地图
Style style = SLD.createSimpleStyle(featureType);
FeatureLayer centroidLayer = new FeatureLayer(featureCollection, style);
map.addLayer(centroidLayer);
System.out.println("Layer hinzugefügt: " + map.layers());

内容的提问来源于stack exchange,提问作者Marc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 12:01:00