QPolygons 边的交点/获取 Qpolygon 边上的所有点

Intersection of QPolygons' edges / Getting all the points on Qpolygon's Edge

我有两个闭合的 QPolygonF,我需要找出它们的边(即它们的轮廓)是否相交。由于这些多边形可能包含在彼此中,因此仅查看多边形的交点是行不通的。

PyQt5 有一个内置函数,用于检查一个点是否在多边形的轮廓线上,contains(QPointF(x,y))。因此,对 QPolygonF 中的每个点使用此方法似乎很明显:

def check_if_two_polygons_share_contour(polygon1,polygon2):
        for i in range(polygon1.size()):
            if polygon2.contains(QPointF(polygon1[i].x(),polygon1[i].y()))
                print("polygon contours touch!")
                return 1
        return 0

但是,由于我的 QPolygons 仅由它们的角点组成,因此这不起作用。

获得构成 QPolygonF 轮廓的所有点似乎是合乎逻辑的下一步,并且 运行 在其上使用相同的函数 (iso polygon1.size())。

应该怎么办?

为了更好地说明这个概念,对于下图中的第 1、4 和 5 个插图,函数应该 return1。


编辑:在此处添加了一些代码以表明某些建议的答案不起作用。

输入:

@alec 建议的函数:

def check_if_two_polygons_share_contour(polygon1,polygon2):
    polygon = polygon1.intersected(polygon2)
    return polygon and polygon not in (polygon1, polygon2)

@Yves Daoust 建议的逻辑:

def line_intersection(line1, line2):
    xdiff = (line1[0][0] - line1[1][0], line2[0][0] - line2[1][0])
    ydiff = (line1[0][1] - line1[1][1], line2[0][1] - line2[1][1])

    def det(a, b):
        return a[0] * b[1] - a[1] * b[0]

    div = det(xdiff, ydiff)
    if div == 0:
        # print("Weak Exception 67892: Lines do not interact (function line_intersection). Return 9999999,9999999")
        return 9999999, 9999999
        # raise Exception('lines do not intersect')

    d = (det(*line1), det(*line2))
    x = det(d, xdiff) / div
    y = det(d, ydiff) / div
    return x, y


def check_if_two_polygons_share_contour(polygon1,polygon2):
    for i in range(polygon1.size()):
        if i != polygon1.size() - 1:
            j = i + 1
            point1 = [polygon1[i].x(), polygon1[i].y()]
            point2 = [polygon1[j].x(), polygon1[j].y()]
            for k in range(polygon2.size()):
                if k != polygon2.size() - 1:
                    l = k + 1
                    point3 = [polygon2[k].x(), polygon2[k].y()]
                    point4 = [polygon2[l].x(), polygon2[l].y()]
                    value_ = line_intersection([point1, point2], [point3, point4])
                    if value_ != (9999999, 9999999):
                        return 1

UI

import PyQt5
from PyQt5 import QtCore
import cv2
import numpy as np
import math
from scipy.ndimage.interpolation import rotate
import sys
import PyQt5
from PyQt5.QtCore import *#QPointF, QRectF
from PyQt5.QtGui import *#QPainterPath, QPolygonF, QBrush,QPen,QFont,QColor, QTransform
from PyQt5.QtWidgets import *#QApplication, QGraphicsScene, QGraphicsView, QGraphicsSimpleTextItem
import math


polycoords1_main_object=[PyQt5.QtCore.QPointF(1162.12, 302.37), PyQt5.QtCore.QPointF(1141.65, 304.13), PyQt5.QtCore.QPointF(1133.45, 307.05), PyQt5.QtCore.QPointF(1124.1, 315.83), PyQt5.QtCore.QPointF(1116.5, 332.2), PyQt5.QtCore.QPointF(1109.48, 365.54), PyQt5.QtCore.QPointF(1099.53, 396.53), PyQt5.QtCore.QPointF(1096.02, 419.93), PyQt5.QtCore.QPointF(1096.62, 457.94), PyQt5.QtCore.QPointF(1100.7, 464.96), PyQt5.QtCore.QPointF(1110.06, 471.98), PyQt5.QtCore.QPointF(1123.51, 471.4), PyQt5.QtCore.QPointF(1129.36, 467.3), PyQt5.QtCore.QPointF(1137.55, 466.13), PyQt5.QtCore.QPointF(1146.91, 466.72), PyQt5.QtCore.QPointF(1155.1, 470.23), PyQt5.QtCore.QPointF(1163.88, 464.38), PyQt5.QtCore.QPointF(1170.3, 450.93), PyQt5.QtCore.QPointF(1170.89, 431.62), PyQt5.QtCore.QPointF(1165.63, 414.07), PyQt5.QtCore.QPointF(1215.0, 448.0), PyQt5.QtCore.QPointF(1227.0, 443.0), PyQt5.QtCore.QPointF(1249.0, 388.0), PyQt5.QtCore.QPointF(1249.0, 362.0), PyQt5.QtCore.QPointF(1240.0, 336.0), PyQt5.QtCore.QPointF(1234.0, 310.0), PyQt5.QtCore.QPointF(1226.0, 288.0), PyQt5.QtCore.QPointF(1227.0, 275.0), PyQt5.QtCore.QPointF(1220.0, 257.0), PyQt5.QtCore.QPointF(1197.0, 247.0), PyQt5.QtCore.QPointF(1174.0, 249.0), PyQt5.QtCore.QPointF(1168.0, 260.0), PyQt5.QtCore.QPointF(1162.0, 278.0), PyQt5.QtCore.QPointF(1179.0, 273.0), PyQt5.QtCore.QPointF(1161.0, 287.0), PyQt5.QtCore.QPointF(1159.0, 291.0)]
polycoords2_secondary_not_touching=[PyQt5.QtCore.QPointF(1234.0, 395.0), PyQt5.QtCore.QPointF(1228.0, 411.0), PyQt5.QtCore.QPointF(1229.0, 417.0), PyQt5.QtCore.QPointF(1209.0, 408.0), PyQt5.QtCore.QPointF(1212.0, 392.0), PyQt5.QtCore.QPointF(1214.0, 390.0)]
polycoords3_secondary_touching = [PyQt5.QtCore.QPointF(1179.0, 401.0), PyQt5.QtCore.QPointF(1169.0, 407.0), PyQt5.QtCore.QPointF(1157.0, 424.0), PyQt5.QtCore.QPointF(1170.0, 448.0), PyQt5.QtCore.QPointF(1178.0, 446.0), PyQt5.QtCore.QPointF(1184.0, 442.0), PyQt5.QtCore.QPointF(1193.0, 434.0), PyQt5.QtCore.QPointF(1193.0, 421.0), PyQt5.QtCore.QPointF(1189.0, 412.0)]
polycoords4_secondary_touching_barely = [PyQt5.QtCore.QPointF(1116.0, 335.0), PyQt5.QtCore.QPointF(1115.0, 346.0), PyQt5.QtCore.QPointF(1111.0, 355.0), PyQt5.QtCore.QPointF(1107.0, 378.0), PyQt5.QtCore.QPointF(1129.0, 381.0), PyQt5.QtCore.QPointF(1130.0, 375.0), PyQt5.QtCore.QPointF(1139.0, 358.0), PyQt5.QtCore.QPointF(1139.0, 347.0), PyQt5.QtCore.QPointF(1141.0, 341.0), PyQt5.QtCore.QPointF(1141.0, 341.0)]

polygon1_main_object= QPolygonF(polycoords1_main_object)
polygon2_secondary_not_touching=QPolygonF(polycoords2_secondary_not_touching)
polygon3_secondary_touching = QPolygonF(polycoords3_secondary_touching)
polygon4_secondary_touching_barely = QPolygonF(polycoords4_secondary_touching_barely)


def main():
    app = QApplication(sys.argv)



    scene = QGraphicsScene()
    view = QGraphicsView(scene)

    a = check_if_two_polygons_share_contour(polygon1_main_object,polygon2_secondary_not_touching)
    if a == 1:
        print("polygon1_main_object and polygon2 touch")
    else:
        print("polygon1_main_object and polygon2 do not touch")

    a = check_if_two_polygons_share_contour(polygon1_main_object, polygon3_secondary_touching)
    if a == 1:
        print("polygon1_main_object and polygon3 touch")
    else:
        print("polygon1_main_object and polygon3do not touch")

    a = check_if_two_polygons_share_contour(polygon1_main_object, polygon4_secondary_touching_barely)
    if a == 1:
        print("polygon1_main_object and polygon4 touch")
    else:
        print("polygon1_main_object and polygon4  do not touch")



    scene.addPolygon(polygon1_main_object,QPen(QColor(0, 20, 0)))

    scene.addPolygon(polygon2_secondary_not_touching, QPen(QColor(240, 20, 0)))

    scene.addPolygon(polygon3_secondary_touching, QPen(QColor(0, 20, 250)))

    scene.addPolygon(polygon4_secondary_touching_barely, QPen(QColor(0, 250, 8)))





    view.show()

    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

musicamante 建议的解决方案:

def return_path_from_points(poly_coords_in):
    path = QPainterPath()

    path.moveTo(poly_coords_in[0])
    for points in poly_coords_in:
        path.lineTo(points)
    path.lineTo(poly_coords_in[0])

    return path


def check_if_two_polygons_share_contour(polygon_coords_a,polygon_coords_b):
    path_a = return_path_from_points(polygon_coords_a)
    path_b = return_path_from_points(polygon_coords_b)

    if path_a.intersects(path_b):
        return 1
    else:
        return 0

当然需要在 UI 文件中编辑 check_if_two_polygons_share_contour 以包含 polycoords iso 多边形 check_if_two_polygons_share_contour(polygon1_main_object,polygon2_secondary_not_touching) ---> check_if_two_polygons_share_contour(polycoords1_main_object, polycoords2_secondary_not_touching)

所有情况的输出:

polygon1_main_object and polygon2 touch
polygon1_main_object and polygon3 touch
polygon1_main_object and polygon4 touch

正确的输出:

polygon1_main_object and polygon2 do not touch
polygon1_main_object and polygon3 touch
polygon1_main_object and polygon4 touch

使用QPolygonF.intersected得到两个多边形的交集。假设两个多边形都像您所说的那样闭合,如果一个多边形完全包含在另一个多边形内,则返回的相交多边形将等于较小的多边形。所以你可以检查它不等于任何一个给定的多边形。

def check_if_two_polygons_share_contour(polygon1, polygon2):
    for x in (polygon1, polygon2):
        if not x.isClosed():
            x << x[0]
    polygon = polygon1.intersected(polygon2)
    return bool(polygon) and polygon not in (polygon1, polygon2)

如果您需要验证拦截但不是遏制,您必须检查两者;以下应该足够了:

def check_if_two_polygons_share_contour(p1, p2):
    path1 = QPainterPath()
    path1.addPolygon(p1)
    path2 = QPainterPath()
    path2.addPolygon(p2)
    return path1.intersects(path2) and not (
        path1.contains(path2) or path2.contains(path1))