检查 OL3 功能相等性的最简单方法

Easiest way to check for OL3 feature equality

我正在从 geojson 文件中加载多个点,并希望删除数据中存在的重复项(对于某些功能,尽管 ID 相同,但属性相同)。为了达到这个目标,我想找出 ol.Feature 个对象是否 等于 其他 ol.Feature 个对象。

相等性是以某种方式在 ol.Feature 对象上定义的还是我必须自己定义它?

具有完全相同属性的两个 ol.Feature 对象不会彼此相等。

是的,您需要手动清除重复项。你说 id 总是唯一的,但其余的有时可能是相同的。在这种情况下,您可以循环使用您的功能。对于每一个,获取所有属性的 JSON 字符串(id 和几何形状除外)并比较新的特征集合。

这里是你如何做到这一点(未经测试,但这可以给你一个想法):

var uniqueFeatures =  [];
var feature;
var properties;
var json;
var jsons = [];
for (var i = 0, ii = features.length; i < ii; i++) {
  feature = features[0];

  // Stringify the properties of the feature
  properties = feature.getProperties();
  var props4json;
  for (var key in properties) {
    if (key !== 'id' && key !== 'geometry') {
      props4json[key] = properties[key];
    }
  }
  json = JSON.stringify(props4json);

  // Check if the stringified properties exist...
  // if not, we have a new unique feature.
  if (jsons.indexOf(json) === -1) {
    jsons.push(json);
    uniqueFeatures(feature);
  }
}

您应该遍历每个功能并获取其属性。 ID 将始终不同,这就是为什么无法使用方法 getFeatureById(来自层或源)或方法 getId(来自单个特征)的原因。

我创建了一个活生生的例子,当你按下按钮时,它可以工作并删除重复的功能。

注意我们正在获取属性 nametag 我们将它们转换成 JSON 变量来比较它们很容易,但您可以 select 满足您需要的属性。

var features = [];
var point1 = ol.proj.transform([-50, 4.678], 'EPSG:4326', 'EPSG:3857');
var point2 = ol.proj.transform([20, 4.678], 'EPSG:4326', 'EPSG:3857');

var feature1 = new ol.Feature({
  geometry: new ol.geom.Point(point1),
  name: "First",
  tag: "TAG"
});
var feature2 = new ol.Feature({
  geometry: new ol.geom.Point(point2),
  name: "Second",
  tag: "TAG"
});

features.push(feature1);
features.push(feature2);
features.push(new ol.Feature({
  geometry: new ol.geom.Point(point1),
  name: "First",
  tag: "TAG"
}));

var vectorSource = new ol.source.Vector({
 features: features
});

var vectorLayer = new ol.layer.Vector({
 source: vectorSource
});

var map = new ol.Map({
  layers: [
    new ol.layer.Tile({
      source: new ol.source.OSM()
    }),
    vectorLayer
  ],
  target: 'map',
  view: new ol.View({
    center: [0, 0],
    zoom: 2
  })
});

document.getElementById("btn").onclick = function(){
  var totalProperties = [];
  vectorSource.getFeatures().forEach(function(feature){
    var propertiesThis = {},
        p = feature.getProperties();

    for (var i in p) {
      if (i === 'name' || i === 'tag') {
        propertiesThis[i] = p[i];
      }
    }
    var jsonProperties = JSON.stringify(propertiesThis);
    
    if (totalProperties.indexOf(jsonProperties) === -1) {
      totalProperties.push(jsonProperties);
    } else {
      vectorSource.removeFeature(feature);
      console.log(propertiesThis['name'] + " feature removed")
    }
  });
};
<link href="https://openlayers.org/en/v3.20.1/css/ol.css" rel="stylesheet"/>
<script src="https://openlayers.org/en/v3.20.1/build/ol.js"></script>
<div id="map" class="map" tabindex="0"></div>

<button id="btn">Remove duplicates</button>

我认为在很大程度上取决于视角和用例来说明特征何时相等,这就是为什么由用户来定义相等性的原因。有些人可能会说,如果特征共享(完全)相同的几何形状 (1),则它们是相等的。其他人可能会说特征需要具有相同的属性 (2) 甚至 (3).

要检查属性相等性,我建议定义对您的相等性定义很重要的属性。然后你可以使用类似这样的代码来检查 2 ol.Feature 个对象是否相等:

// Define your important properties    
var mySelectedProperties = ["importantProperty", "anotherImportantProperty", "propertyX"];

// Check for property equality between two ol.Feature objects
function areEqual(featureA, featureB){
    var equal = true;
    for(let property of mySelectedProperties){
        if(featureA.get(property) != featureB.get(property)){
            equal = false;        
            return equal ;
        }
    }
    return equal;
}

对于几何相等,您可能需要检查 (x & y) 坐标是否相同。这里还有一些注意事项:

  • 2 个几何形状可能看起来相同,但坐标顺序不同:

例如:lineA:pointA-pointBlineB:pointB-pointA

甚至这样:polygonA: pointA-pointB-pointC-pointA and polygonB: pointB-pointC-pointA-pointB

  • 对于某些特征,说几何与另一个几何非常接近以至于它可能代表相同的特征可能是有意义的...(例如(小的)测量误差或浮点不准确)。