pyqt5geometrypolygonqtguiqpolygon

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


I have two closed QPolygonFs and I need to find out whether their edges (that is their contours) intersect. As these polygons may be included in one another, looking simply at the intersection of the polygons does not work.

PyQt5 has a built-in function for checking if a point is on the contourline of the polygon, contains(QPointF(x,y)). Thus, it seemed obvious to use this method for each point in the 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

However, as my QPolygons are made up only of their cornerpoints, this does not work.

It seems like the logical next step to get all of the points that make up the QPolygonF's contour, and run the same function on it (iso polygon1.size()).

How should one go about this?

To illustrate the concept a bit better, the function should return 1 for the 1st, 4th and 5th illustration in the image below.

Illustration


Edit: Added some code here to show that some of the suggested answers do not work.

Input:

Function suggested by @alec:

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

Logic suggested by @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()

The solution as suggested by 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

and ofcourse one needs to edit check_if_two_polygons_share_contour in the UI file to include polycoords iso polygons 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)

output for all cases:

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

The output that would be correct:

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

Output


Solution

  • If you need to verify the interception but not the containement, you have to check for both; the following should suffice:

    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))