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))
我有两个闭合的 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))