pythonpyqt5qgraphicssceneqpolygon

PyQt5: Centre line of a QPolygonF


I'm trying to get the centre line of a QPolygonF object, meaning the line that is in the middle of min and max X coordinate, for every single y coordinate from min to max.

The desired output would be a single centre line, yet for some reason the drawn object/ central line has area. Why is that the case & what should I do to get the centre line? As roughly estimated with the black line in the image below

enter image description here

Here's the code:

import PyQt5
from PyQt5 import QtGui
from PyQt5.QtWidgets import QApplication,QWidget, QMainWindow,QVBoxLayout, QGraphicsScene, QGraphicsPixmapItem,QGraphicsView
from PyQt5.QtGui import QPixmap,QPolygonF
from PyQt5.QtCore import Qt,QPointF
import sys
import time
class MainWindow(QMainWindow):

    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        self.setFixedSize(1200, 800)

        self.ImageDisplay = QGraphicsView()

        self.qwidget = QWidget()

        qpixmap = QPixmap()
        qpixmap2 = qpixmap.scaledToWidth(self.ImageDisplay.width())
        qgraphicsitem = QGraphicsPixmapItem(qpixmap2)
        qscene = QGraphicsScene(self.ImageDisplay)
        qscene.addItem(qgraphicsitem)
        self.ImageDisplay.setScene(qscene)
        self.ImageDisplay.setMouseTracking(True)
        self.ImageDisplay.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
        self.ImageDisplay.setResizeAnchor(QGraphicsView.AnchorUnderMouse)
        self.ImageDisplay.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.ImageDisplay.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        start = time.time()

        poly = QPolygonF([QPointF(400, 400), QPointF(100, 10), QPointF(20, 100), QPointF(0, 400)])#, QPointF(105, 5), QPointF(9, 300)])

        min_y, max_y = poly.boundingRect().y(), poly.boundingRect().y() + poly.boundingRect().height()
        min_x,max_x =  poly.boundingRect().x(), poly.boundingRect().x() + poly.boundingRect().width()
        print("min_y="+str(min_y)+", max_y="+str(max_y))
        print("min_x=" + str(min_x) + ", max_x=" + str(max_x))
        end = time.time()
        print(f"runtime: {end - start}")

        middle_points= []
        for y in range(int(min_y),int(max_y)):
           # for x in range(int(min_x),int(max_x)):
            polyline = QPolygonF([QPointF(min_x,y),QPointF(max_x,y),QPointF(min_x,y+0.1),QPointF(max_x,y+0.1)])

            intersection_points = poly.intersected(polyline)


            intersection_points = intersection_points.boundingRect()

            middle_point = QPointF(intersection_points.x()+intersection_points.width()/2,intersection_points.y()+intersection_points.height()/2)
            middle_points.append(middle_point)


        middle_poly = QPolygonF(middle_points)
        self.ImageDisplay.scene().addPolygon(middle_poly, QtGui.QColor(20, 0, 255, 28),
                                             QtGui.QColor(20, 0, 255, 28))

        end = time.time()
        print(f"runtime: {end - start}")






        self.vlayout = QVBoxLayout()
        self.vlayout.addWidget(self.ImageDisplay)

        self.qwidget.setLayout(self.vlayout)

        self.setCentralWidget(self.qwidget)


app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()

Solution

  • You have to take into account that:

    To draw the central curve then you have to use QPainterPath, in addition to using np.arange().

    import sys
    
    from PyQt5.QtCore import QPointF, QRectF
    from PyQt5.QtGui import QPainterPath, QPolygonF
    from PyQt5.QtWidgets import QApplication, QGraphicsScene, QGraphicsView
    
    import numpy as np
    
    
    def build_center_line(polygon):
        points = []
        minx, miny, maxx, maxy = polygon.boundingRect().getCoords()
        dy = (maxy - miny) / 200
        for y in np.arange(miny, maxy, dy):
            polyline = QPolygonF(
                QRectF(QPointF(minx, y - dy / 2), QPointF(maxx, y + dy / 2))
            )
            p = polygon.intersected(polyline).boundingRect().center()
            points.append(p)
        return points
    
    
    def main():
        app = QApplication(sys.argv)
        polygon = QPolygonF(
            [QPointF(400, 400), QPointF(100, 10), QPointF(20, 100), QPointF(0, 400)]
        )
    
        points = build_center_line(polygon)
        path = QPainterPath()
        if points:
            path.moveTo(points[0])
            for point in points[1:]:
                path.lineTo(point)
    
        scene = QGraphicsScene()
        view = QGraphicsView(scene)
        scene.addPolygon(polygon)
        scene.addPath(path)
        view.resize(640, 480)
        view.show()
    
        sys.exit(app.exec_())
    
    
    if __name__ == "__main__":
        main()
    

    enter image description here