【问题标题】:How to precisely check if one polygon overlaps another while ignoring boundary如何在忽略边界的情况下精确检查一个多边形是否与另一个多边形重叠
【发布时间】:2019-10-03 17:45:08
【问题描述】:

我有一个关于开放层中多边形之间的拓扑和关系的问题。

情况是这样的:

使用https://turfjs.org/ 我正在使用两种方法来检查多边形是否重叠,https://turfjs.org/docs/#booleanOverlaphttps://turfjs.org/docs/#booleanWithin 但我得到了一些奇怪的交互。

如您所见,在蓝色 rectangle 中,多边形被捕捉到红色多边形,这是很好的行为,但问题是黄色矩形中的多边形我得到 true em> 并自动重叠红色样式。蓝色多边形和黄色矩形多边形仅捕捉到红色多边形的边界。

所以,我的问题是这样的;是否有可能以某种方式忽略限制性多边形(红色)的边界,或者我应该找到另一种方法。

我正在检查多边形是否重叠的代码示例:

 vectorLayer.getSource().on(OpenLayersEvents.AddFeature, (evt: any) => {


            let feature = evt.feature;


            // clip area function with return geometry value
            let polygon = clipFieldArea(feature, this.myRestrictionVectorLayer);


            let isFeatureOverlappingFlag = false;
            //red polygons
            if (this.restrictiveLayer.getSource().getFeatures().length > 0) {
                isFeatureOverlappingFlag = arePolygonsOverlapping(feature, this.restrictiveLayer); 
            }

            // checks if features are overlapping then set new style
            feature.getGeometry().setCoordinates(polygon.getCoordinates());
            if (isFeatureOverlappingFlag) {
                feature.setStyle(this.featureOverlappingStyle);
            } else {
                feature.setStyle(this.fieldStyle);
            }....

这是检查拓扑的 arePolygonsOverlapping() 方法

   let geojsonFormat = new GeoJSON();

    let areOverlapping: boolean = false;

    let flagCheck: boolean = false;
    let restrictionFeatures = restrictionLayer.getSource().getFeatures();

    // create GeoJSON object and transform it in WGS84 for intersect method
    let firstGeometryObject = geojsonFormat.writeFeatureObject(feature, { dataProjection: 'EPSG:4326', featureProjection: 'EPSG:3857' });

    for (let featureRestrict of restrictionFeatures) {

        let secondGeometryObject = geojsonFormat.writeFeatureObject(featureRestrict,
            { dataProjection: 'EPSG:4326', featureProjection: 'EPSG:3857' });

        areOverlapping = booleanOverlap(firstGeometryObject as unknown as TurfPolygon, secondGeometryObject as unknown as TurfPolygon);

        if (areOverlapping) {
            flagCheck = true;
            break;
        }
    }
    return flagCheck;

更新

我尝试使用 Mike 提出的解决方案,但我收到了 Uncaught TypeError: ol_proj__WEBPACK_IMPORTED_MODULE_3__.default.Projection is not a constructor

尝试创建新投影时。 这是更新的方法

export function arePolygonsOverlapping(feature: any, restrictionLayer: VectorLayer): boolean {

    let areOverlapping: boolean = false;

    let flagCheck: boolean = false;
    let restrictionFeatures = restrictionLayer.getSource().getFeatures();

    //#region "Parameters for scaling down coordinates"
        let viewProjection = Projection.get('EPSG:3857');
        let smallProjection = Projection.get('small');

    if (!smallProjection) {
        smallProjection = new Projection.Projection({
            code: 'small',
            units: 'm'
        });

        Projection.addProjection(smallProjection);

        let scale = Extent.getWidth(viewProjection.getExtent());

        let smallTransform = function (coordinate: [number, number]) {
            return [coordinate[0] / scale, coordinate[1] / scale];
        }

        let normalTransform = function (coordinate: [number, number]) {
            return [coordinate[0] * scale, coordinate[1] * scale];
        }

        Projection.addCoordinateTransforms(viewProjection, smallProjection, smallTransform as any, normalTransform as any);

    }
    //#endregion "Parameters for scaling down coordinates"


    // create GeoJSON object and transform it in WGS84 for intersect method
    let firstGeometryObject = geojsonFormat.writeFeatureObject(feature, { dataProjection: smallProjection, featureProjection: viewProjection  });

    for (let featureRestrict of restrictionFeatures) {

        let secondGeometryObject = geojsonFormat.writeFeatureObject(featureRestrict,
            { dataProjection: smallProjection, featureProjection: viewProjection  });

        areOverlapping = booleanOverlap(firstGeometryObject as unknown as TurfPolygon, secondGeometryObject as unknown as TurfPolygon);

        if (areOverlapping) {
            flagCheck = true;
            break;
        }
    }
    return flagCheck;
}

这是我的导入:

import Extent from 'ol/extent';
import Projection from 'ol/proj';

我忘了说我使用的是 v 4.6.2

【问题讨论】:

  • 是否需要更改 writeFeatureObject 中的投影?一个投影中的重叠可能不会在另一个投影中重叠。- 请参阅gis.stackexchange.com/questions/308871/…
  • @Mike 嗨,Mike,感谢您的回答。我相信我必须这样做,因为 Turf 库希望数据是标准 WGS84 经度、纬度坐标。
  • 这肯定是一些草皮功能的问题(特别是如果它们使用公差),而其他只是使用提供的数字。如有必要,您可以定义一个虚拟投影,将您的 EPSG:3857 坐标减少到足够小的值,以便草坪将 WGS84 处理它们而不影响重新投影正常的形状 - 请参阅gis.stackexchange.com/questions/317657/…
  • @Mike 谢谢。我也在考虑另一种方法,比如说使用 JSTS 或以某种方式检测边框是否重叠
  • @Mike Mike,只需将您的评论与一些代码示例一起回答以接受它

标签: openlayers openlayers-3 openlayers-5 topology turfjs


【解决方案1】:

我已经测试了booleanOverlap,尽管它似乎确实适用于任何投影中的数字,但为了符合草皮规范,建议通过缩小 EPSG:3857 坐标而不转换为改变多边形形状的投影。缩放转换也可以比评论链接中的更简单。

import { getWidth } from 'ol/extent';
import { Projection, addCoordinateTransforms, addProjection, get as getProjection } from 'ol/proj';

....
....


let viewProjection = getProjection('EPSG:3857');
let smallProjection = getProjection('small');

if (!smallProjection) {

    smallProjection = new Projection({
        code: 'small',
        units: 'm'
    });
    addProjection(smallProjection);

    let scale = getWidth(viewProjection.getExtent());

    let smallTransform = function(coordinate) {
        return [coordinate[0] / scale, coordinate[1] / scale];
    }

    let normalTransform = function(coordinate) {
        return [coordinate[0] * scale, coordinate[1] * scale];
    }

    addCoordinateTransforms(viewProjection, smallProjection, smallTransform, normalTransform);

}

let geojsonFormat = new GeoJSON();

let areOverlapping: boolean = false;

let flagCheck: boolean = false;
let restrictionFeatures = restrictionLayer.getSource().getFeatures();

// create GeoJSON object and transform it in WGS84 for intersect method
let firstGeometryObject = geojsonFormat.writeFeatureObject(feature, { dataProjection: smallProjection, featureProjection: viewProjection });

for (let featureRestrict of restrictionFeatures) {

    let secondGeometryObject = geojsonFormat.writeFeatureObject(featureRestrict,
        { dataProjection: smallProjection, featureProjection: viewProjection });

    areOverlapping = booleanOverlap(firstGeometryObject as unknown as TurfPolygon, secondGeometryObject as unknown as TurfPolygon);

    if (areOverlapping) {
        flagCheck = true;
        break;
    }
}
return flagCheck;

【讨论】:

  • 迈克,感谢您的努力,但我在尝试创建新投影时出错
【解决方案2】:

好的,我在这件事上采取了不同的方式。而不是“修复”和调整坐标(尽管如此,在 Mike 的回答中很好地指出我们应该缩小坐标)

我刚刚使用了 Turf intersected 方法并通过附加区域检查检查是否有任何相交特征。

这种方法涵盖了我一直在尝试的大多数情况

let isIntersecting: boolean = false;

let flagCheck: boolean = false;
let restrictionFeatures = restrictionLayer.getSource().getFeatures();

// create GeoJSON object and transform it in WGS84 for intersect method
let firstGeometryObject = geojsonFormat.writeFeatureObject(feature, { dataProjection: 'EPSG:4326', featureProjection: 'EPSG:3857' }) as unknown as TurfPolygon;

for (let featureRestrict of restrictionFeatures) {

    let secondGeometryObject = geojsonFormat.writeFeatureObject(featureRestrict,
        { dataProjection: 'EPSG:4326', featureProjection: 'EPSG:3857' }) as unknown as TurfPolygon;

    // get intersected polgon
    let intersectPolygon = intersect(firstGeometryObject, secondGeometryObject);

    if (intersectPolygon != null) {
        isIntersecting = true;

        // calculate value of intersected area
        let areaValue: number = area(intersectPolygon as unknown as AllGeoJSON);

        // area below 10 meters is considered overlapping
        if (areaValue < 10) {
            isIntersecting = false;
        }
    }

    if (isIntersecting) {
        flagCheck = true;
        break;
    }
}
return flagCheck;

【讨论】:

    猜你喜欢
    • 2018-03-09
    • 1970-01-01
    • 2019-08-23
    • 1970-01-01
    • 2023-03-22
    • 2020-06-19
    • 1970-01-01
    • 2014-01-24
    • 1970-01-01
    相关资源
    最近更新 更多