D'une manière ou d'une autre, quand je regardais la documentation PyQt Graph, j'ai remarqué qu'il y avait une fonction 3D Graphics dans l'API. J'étais curieux, j'ai donc essayé de créer une application graphique simple qui affiche un modèle 3D en combinaison avec PyQt5.
Comme j'utilise souvent des imprimantes 3D, le modèle 3D fait ici référence au format de fichier STL.
Vous pouvez afficher le fichier STL sous forme filaire en sélectionnant ou en faisant glisser et en déposant le fichier STL. C'est un programme simple qui n'affiche qu'un seul fichier STL à la fois. Le code est également sur GitHub. GitHub:https://github.com/Be4rR/STLViewer
PyQtGraph est une bibliothèque pour dessiner des graphiques et peut être utilisé seul, mais vous pouvez facilement intégrer le graphique créé dans une interface graphique créée par PyQt. Bien que sa fonction soit plus faible que le Matplotlib standard, il est très léger et convient pour tracer des données en temps réel. C'est une bibliothèque peu connue, mais personnellement je la trouve utile. Page officielle: http://www.pyqtgraph.org/ Document officiel: https://pyqtgraph.readthedocs.io/en/latest/index.html
J'utilise Python3.8, PyQt5, PyQtGraph, PyOpenGL, Numpy et Numpy-STL. PyOpenGL est requis pour utiliser les fonctions graphiques 3D avec PyQtGraph. Lisez également le fichier STL avec Numpy-STL.
conda create -n stlviewer python=3.8 pyqt pyqtgraph numpy numpy-stl pyopengl
C'est un peu long.
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_()
Ce n'est pas trop compliqué, mais je vais vous expliquer quelques points clés.
GLViewWidget
Divers éléments graphiques sont répertoriés dans le Système graphique 3D de la documentation PyQtGraph.
Le premier GLViewWidget
est un widget pour afficher des modèles 3D. Nous ajouterons le deuxième élément graphique et les suivants à ce widget. Par exemple, GLGridItem
peut être utilisé pour ajouter un plan de grille, et GLMeshItem
peut être utilisé pour ajouter des données de maillage telles qu'un fichier STL. Consultez la documentation officielle pour plus de détails.
Puisque GLViewWidget
peut être manipulé exactement de la même manière que le widget de PyQt, il peut être intégré dans l'interface graphique de PyQt tel quel.
def showSTL(self, filename):
#Si un autre modèle 3D est déjà affiché, supprimez ce modèle 3D.
if self.currentSTL:
self.viewer.removeItem(self.currentSTL)
#Extrayez les points de sommet et les faces des faces du fichier STL.
points, faces = self.loadSTL(filename)
#Un widget qui crée un maillage et affiche un modèle 3D(self.viewer)Ajouter à.
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
La fonction loadSTL
extrait les informations de sommet et de face du fichier STL. Les «points» et «faces» sont des tableaux Numpy, où «points» se présente sous la forme de »(nombre de sommets, 3)« et »faces» est sous la forme de «(nombre de faces, 3)».
Dans le programme ci-dessus, les informations sur les sommets et les faces sont transmises à MeshData
pour créer meshdata
, et sur cette base, gl.GLMeshItem
est créé pour déterminer la méthode de dessin (couleurs des faces et des côtés, etc.) Il y a deux étapes.
Ajoutez ensuite le «GLMeshItem» créé au «GLViewWidget» «self.viewer».
self.viewer.addItem(mesh)
La grille est également le même élément graphique que GLMeshItem
, donc il peut être affiché de la même manière.
Partie de fonction ʻInitUI`.
g = gl.GLGridItem()
g.setSize(200, 200)
g.setSpacing(5, 5)
self.viewer.addItem(g)
Après avoir créé avec GLGridItem ()
, la taille est décidée par la fonction setSize
, et la taille d'une grille est spécifiée par la fonction setSpacing
. Enfin, ajoutez-le à self.viewer
de GLViewWidget
avec la fonction ʻaddItem`.
Recommended Posts