Als ich mir die PyQt Graph-Dokumentation ansah, bemerkte ich irgendwie, dass die API eine 3D-Grafikfunktion enthielt. Ich war neugierig und habe versucht, eine einfache GUI-Anwendung zu erstellen, die ein 3D-Modell in Kombination mit PyQt5 anzeigt.
Da ich häufig 3D-Drucker verwende, bezieht sich das 3D-Modell hier auf das STL-Dateiformat.
Sie können die STL-Datei im Drahtmodell anzeigen, indem Sie die STL-Datei auswählen oder ziehen und ablegen. Es ist ein einfaches Programm, das jeweils nur eine STL-Datei anzeigt. Der Code ist auch auf GitHub. GitHub:https://github.com/Be4rR/STLViewer
PyQtGraph ist eine Bibliothek zum Zeichnen von Diagrammen und kann allein verwendet werden. Sie können das erstellte Diagramm jedoch problemlos in eine von PyQt erstellte GUI einbetten. Obwohl seine Funktion schwächer ist als die von Standard-Matplotlib, ist es sehr leicht und eignet sich zum Zeichnen von Daten in Echtzeit. Es ist eine wenig bekannte Bibliothek, aber ich persönlich finde sie nützlich. Offizielle Seite: http://www.pyqtgraph.org/ Offizielles Dokument: https://pyqtgraph.readthedocs.io/en/latest/index.html
Ich verwende Python3.8, PyQt5, PyQtGraph, PyOpenGL, Numpy und Numpy-STL. PyOpenGL ist erforderlich, um 3D-Grafikfunktionen mit PyQtGraph zu verwenden. Lesen Sie auch die STL-Datei mit Numpy-STL.
conda create -n stlviewer python=3.8 pyqt pyqtgraph numpy numpy-stl pyopengl
Es ist ein bisschen lang.
from pyqtgraph.Qt import QtCore, QtGui
import pyqtgraph as pg
import pyqtgraph.opengl as gl
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import numpy as np
from stl import mesh
from pathlib import Path
class MyWindow(QMainWindow):
def __init__(self):
super(MyWindow, self).__init__()
self.setGeometry(0, 0, 700, 900)
self.setAcceptDrops(True)
self.initUI()
self.currentSTL = None
self.lastDir = None
self.droppedFilename = None
def initUI(self):
centerWidget = QWidget()
self.setCentralWidget(centerWidget)
layout = QVBoxLayout()
centerWidget.setLayout(layout)
self.viewer = gl.GLViewWidget()
layout.addWidget(self.viewer, 1)
self.viewer.setWindowTitle('STL Viewer')
self.viewer.setCameraPosition(distance=40)
g = gl.GLGridItem()
g.setSize(200, 200)
g.setSpacing(5, 5)
self.viewer.addItem(g)
btn = QPushButton(text="Load STL")
btn.clicked.connect(self.showDialog)
btn.setFont(QFont("Ricty Diminished", 14))
layout.addWidget(btn)
def showDialog(self):
directory = Path("")
if self.lastDir:
directory = self.lastDir
fname = QFileDialog.getOpenFileName(self, "Open file", str(directory), "STL (*.stl)")
if fname[0]:
self.showSTL(fname[0])
self.lastDir = Path(fname[0]).parent
def showSTL(self, filename):
if self.currentSTL:
self.viewer.removeItem(self.currentSTL)
points, faces = self.loadSTL(filename)
meshdata = gl.MeshData(vertexes=points, faces=faces)
mesh = gl.GLMeshItem(meshdata=meshdata, smooth=True, drawFaces=False, drawEdges=True, edgeColor=(0, 1, 0, 1))
self.viewer.addItem(mesh)
self.currentSTL = mesh
def loadSTL(self, filename):
m = mesh.Mesh.from_file(filename)
shape = m.points.shape
points = m.points.reshape(-1, 3)
faces = np.arange(points.shape[0]).reshape(-1, 3)
return points, faces
def dragEnterEvent(self, e):
print("enter")
mimeData = e.mimeData()
mimeList = mimeData.formats()
filename = None
if "text/uri-list" in mimeList:
filename = mimeData.data("text/uri-list")
filename = str(filename, encoding="utf-8")
filename = filename.replace("file:///", "").replace("\r\n", "").replace("%20", " ")
filename = Path(filename)
if filename.exists() and filename.suffix == ".stl":
e.accept()
self.droppedFilename = filename
else:
e.ignore()
self.droppedFilename = None
def dropEvent(self, e):
if self.droppedFilename:
self.showSTL(self.droppedFilename)
if __name__ == '__main__':
app = QtGui.QApplication([])
window = MyWindow()
window.show()
app.exec_()
Es ist nicht zu kompliziert, aber ich werde einige wichtige Punkte erklären.
GLViewWidget
Verschiedene Grafikelemente sind in der 3D-Grafiksystem der PyQtGraph-Dokumentation aufgeführt.
Das erste GLViewWidget ist ein Widget zum Anzeigen von 3D-Modellen. Wir werden das zweite und nachfolgende Grafikelemente zu diesem Widget hinzufügen. Beispielsweise kann "GLGridItem" zum Hinzufügen einer Rasterebene und "GLMeshItem" zum Hinzufügen von Netzdaten wie einer STL-Datei verwendet werden. Einzelheiten finden Sie in der offiziellen Dokumentation.
Da GLViewWidget
genauso behandelt werden kann wie das Widget von PyQt, kann es so wie es ist in die GUI von PyQt eingebettet werden.
def showSTL(self, filename):
#Wenn bereits ein anderes 3D-Modell angezeigt wird, entfernen Sie dieses 3D-Modell.
if self.currentSTL:
self.viewer.removeItem(self.currentSTL)
#Extrahieren Sie die Scheitelpunkte und Flächen aus der STL-Datei.
points, faces = self.loadSTL(filename)
#Ein Widget, das ein Netz erstellt und ein 3D-Modell anzeigt(self.viewer)Hinzufügen.
meshdata = gl.MeshData(vertexes=points, faces=faces)
mesh = gl.GLMeshItem(meshdata=meshdata, smooth=True, drawFaces=False, drawEdges=True, edgeColor=(0, 1, 0, 1))
self.viewer.addItem(mesh)
self.currentSTL = mesh
Die Funktion loadSTL
extrahiert Scheitelpunkt- und Gesichtsinformationen aus der STL-Datei. Sowohl "Punkte" als auch "Flächen" sind Numpy-Arrays, wobei "Punkte" in Form von "(Anzahl der Eckpunkte, 3)" und "Flächen" in Form von "(Anzahl der Flächen, 3)" vorliegen.
Im obigen Programm werden die Informationen von Scheitelpunkten und Flächen an "MeshData" übergeben, um "MeshData" zu erstellen, und basierend darauf wird "gl.GLMeshItem" erstellt, um die Zeichenmethode (Gesichts- und Seitenfarben usw.) zu bestimmen. Es gibt zwei Schritte.
Fügen Sie dann das erstellte GLMeshItem
zum GLViewWidget`` self.viewer
hinzu.
self.viewer.addItem(mesh)
Das Raster ist auch das gleiche Grafikelement wie "GLMeshItem", sodass es auf die gleiche Weise angezeigt werden kann.
Dies ist der Teil der Funktion initUI
.
g = gl.GLGridItem()
g.setSize(200, 200)
g.setSpacing(5, 5)
self.viewer.addItem(g)
Nach dem Erstellen mit "GLGridItem ()" wird die Größe durch die Funktion "setSize" festgelegt, und die Größe eines Rasters wird durch die Funktion "setSpacing" festgelegt. Fügen Sie es schließlich mit der Funktion "addItem" zu "self.viewer" von "GLViewWidget" hinzu.
Recommended Posts