PyQt5: Центральная линия QPolygonF

avatar
usario121233
8 августа 2021 в 19:42
127
1
0

Я пытаюсь получить центральную линию объекта QPolygonF, то есть линию, которая находится посередине минимальной и максимальной координаты X, для каждой отдельной координаты y от минимальной до максимальной.

На выходе должна быть одна центральная линия, но по какой-то причине нарисованный объект/центральная линия имеет площадь. Почему это так и что я должен сделать, чтобы получить центральную линию? Примерно по черной линии на изображении ниже

enter image description here

Вот код:

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_()
Источник
eyllanesc
8 августа 2021 в 19:45
1

Как вы определяете «центральную линию»? Как вы уверены, что есть такая "центральная линия"? Основано ли оно на какой-то математической теореме?

musicamante
8 августа 2021 в 19:46
1

Не могли бы вы уточнить, что вы подразумеваете под «осевой линией», возможно, с графическим макетом ожидаемого результата?

usario121233
8 августа 2021 в 19:50
0

Конечно, извините, что не было яснее раньше. Отредактировал вопрос, чтобы включить изображение того, что я хотел бы получить.

eyllanesc
8 августа 2021 в 19:53
1

@ usario121233 usario121233 Думаю, эту концепцию можно применить только к выпуклым многоугольникам, а как насчет невыпуклых многоугольников? Как было бы в таком случае?

usario121233
8 августа 2021 в 20:11
0

@eyllanesc Точно, только для выпуклых многоугольников: все многоугольники внутри полной программы выпуклые.

Ответы (1)

avatar
eyllanesc
8 августа 2021 в 20:36
3

Вы должны принять во внимание, что:

  • При добавлении QPolygon будет нарисована замкнутая фигура.
  • Это не центральная линия, а центральная кривая, состоящая из отрезков.
  • Код for y in range(int(min_y),int(max_y)): работает с (ymax-ymin) больше 1, но не работает в других случаях.

Чтобы нарисовать центральную кривую, вы должны использовать QPainterPath в дополнение к использованию 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

eyllanesc
9 августа 2021 в 15:19
1

@usario121233 usario121233, возможно, помогает метод length QPainterPath, с другой стороны, у вас есть точки, поэтому вы можете рассчитать расстояние между последовательными точками и добавить их

usario121233
9 августа 2021 в 15:21
0

Понятно! Ваше здоровье! Из любопытства - почему dy = (maxy - miny) / 200 --> Откуда берется 200?

eyllanesc
9 августа 2021 в 15:37
1

@usario121233 usario121233 Это служит для отображения точек. Число 200 — это количество баллов, которое берется между значениями Y, чем выше значение, тем точнее расчет.

usario121233
9 августа 2021 в 15:47
0

Глядя на это после чашки кофе, это имеет смысл, извините за глупый/очевидный вопрос. Огромное спасибо за помощь, eyllanesc!