PythonOcc实战

您所在的位置:网站首页 几何设计图 PythonOcc实战

PythonOcc实战

2024-03-20 02:17| 来源: 网络整理| 查看: 265

本系列文章主要是基于PythonOcc模块进行实例编程。本文主要想实现的功能是将step模型文件加载并封装到pyqt5自制的UI界面中,并初步实现零件识别、零件几何属性计算、产品爆炸图初步展示。 阅读并实现本系列文章需要一定的基础,请参考: 小新快跑

import sys from PyQt5.QtWidgets import QMainWindow, QAction, qApp, QApplication from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeBox#引入Occ模型绘制模块 from SelfMadeQTviewer3D import qtViewer3d#引入自己修改后的Occ3维模型展示模块,该模块并不通用, #是由本人修改源代码之后才能使用的,源代码中不能直接import qtViewer3d #该代码参考https://blog.csdn.net/weixin_42755384/article/details/87925748 class Example(QMainWindow): def __init__(self): super().__init__() self.canva = qtViewer3d(self) self.initUI() def initUI(self): exitAct = QAction('&Exit', self) exitAct.setShortcut('Ctrl+Q') exitAct.setStatusTip('Exit application') exitAct.triggered.connect(qApp.quit) self.statusBar() menubar = self.menuBar() fileMenu = menubar.addMenu('&File') fileMenu.addAction(exitAct) self.setGeometry(300, 100, 1600, 800) self.setWindowTitle('PyOcc Packed In Pyqt5') boxshp = BRepPrimAPI_MakeBox(50., 50., 50.).Shape()#绘制occ3维CAD模型 self.canva._display.DisplayShape(boxshp, update=True)[0]#在画布上展示occ3维CAD模型 self.setCentralWidget(self.canva)#在画布上展示occ3维CAD模型 self.show() if __name__ == '__main__': app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_())

以上代码可以得到将occ封装入自定义pyqt5的UI界面,如下图所示,关键是: from SelfMadeQTviewer3D import qtViewer3d。 在这里插入图片描述

接下来将进入实战。将STEP文件导入到PythonOcc中并实现零件识别、零件几何属性计算:

import sys import time from math import pi import random from OCC.Core.gp import gp_Ax1, gp_Pnt, gp_Dir, gp_Trsf # 引入Occ模型几何尺寸元素模块 from OCC.Core.TopLoc import TopLoc_Location # 引入Occ模型定位模块 from PyQt5.QtWidgets import QMainWindow, QAction, qApp, QApplication from SelfMadeQTviewer3D import qtViewer3d # 引入自己修改后的Occ3维模型展示模块 from OCC.Extend.DataExchange import read_step_file#STEP文件导入模块 from OCC.Extend.TopologyUtils import TopologyExplorer#STEP文件导入模块后的拓扑几何分析模块 from OCC.Core.Quantity import Quantity_Color, Quantity_TOC_RGB from OCC.Core.GProp import GProp_GProps#几何模型属性 from OCC.Core.BRepGProp import brepgprop_VolumeProperties#solid几何模型属性 class Example(QMainWindow): def __init__(self): super().__init__() self.canva = qtViewer3d(self) self.initUI() def initUI(self): exitAct = QAction('&Exit', self) exitAct.setShortcut('Ctrl+Q') exitAct.setStatusTip('Exit application') exitAct.triggered.connect(qApp.quit) self.statusBar() menubar = self.menuBar() fileMenu = menubar.addMenu('&File') fileMenu.addAction(exitAct) self.setGeometry(100, 50, 1200, 900) self.setWindowTitle('PyOcc Packed In Pyqt5') self.setCentralWidget(self.canva) self.StepModelExplore() self.show() def STEP_shape(self): stpshp = read_step_file('GateValveAssembly.STEP')# 读取step文件 return TopologyExplorer(stpshp)# step文件模型解析 def StepModelExplore(self): self.canva._display.EraseAll() self.STEPshp = self.STEP_shape() i=0 for solid in self.STEPshp.solids(): i=i+1#用于统计零件数目 props = GProp_GProps()#获取几何属性查询函数 brepgprop_VolumeProperties(solid, props)#计算出当前solid的集合属性 #matrix_of_inertia = props.MatrixOfInertia()#当前solid的惯性矩 cog = props.CentreOfMass()#当前solid的形心 cog_x, cog_y, cog_z = cog.Coord() print("This Solid mass = %s" % props.Mass())#当前solid的体积 print("Center of Solid: x = %f;y = %f;z = %f;" % (cog_x, cog_y, cog_z)) color = Quantity_Color(random.random(), random.random(),random.random(),Quantity_TOC_RGB) self.canva._display.DisplayColoredShape(solid, color) print("零件数目为:%d" % (i)) self.canva._display.FitAll() if __name__ == '__main__': app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_()) 2 Number of shapes: 2 This Solid mass = 1671588.029631332 Center of Solid: x = 0.000025;y = 21.327333;z = -90.000000; This Solid mass = 20416.786227435936 Center of Solid: x = -0.000001;y = 0.723585;z = -67.780266; This Solid mass = 20416.786227435958 Center of Solid: x = -0.000000;y = 0.723584;z = -112.219734; This Solid mass = 539264.8949639023 Center of Solid: x = -0.053763;y = 166.657923;z = -90.042440; This Solid mass = 54103.19372018658 Center of Solid: x = -0.000000;y = 311.553234;z = -90.000000; This Solid mass = 18954.852646672913 Center of Solid: x = -0.000000;y = 305.792553;z = -90.000000; This Solid mass = 338469.4612692211 Center of Solid: x = 0.000015;y = 337.857166;z = -90.000001; This Solid mass = 5220.770297180713 Center of Solid: x = 0.000000;y = 344.000954;z = -90.000000; This Solid mass = 49449.28479252284 Center of Solid: x = -0.000000;y = 114.460108;z = -90.000000; This Solid mass = 39139.64044792523 Center of Solid: x = -0.199089;y = 283.199322;z = -90.325002; This Solid mass = 106966.64358232789 Center of Solid: x = -0.000000;y = 11.964572;z = -90.000007; This Solid mass = 4781.860167653959 Center of Solid: x = -2.724443;y = 192.999999;z = -42.000000; This Solid mass = 1309.926227762865 Center of Solid: x = 20.706363;y = 193.000002;z = -42.000000; This Solid mass = 12662.473567635041 Center of Solid: x = 0.000000;y = 214.240225;z = -42.000000; This Solid mass = 4781.860167653957 Center of Solid: x = -2.724443;y = 192.999999;z = -138.000000; This Solid mass = 1309.9262277628643 Center of Solid: x = 20.693637;y = 193.000002;z = -138.000000; This Solid mass = 12662.473567635043 Center of Solid: x = 0.000000;y = 214.240225;z = -138.000000; This Solid mass = 36769.10249043011 Center of Solid: x = 0.000000;y = 232.763354;z = -89.999999; This Solid mass = 10777.165686221655 Center of Solid: x = -0.000000;y = 214.799317;z = -90.000000; This Solid mass = 1998.9380995506442 Center of Solid: x = -0.000003;y = 244.471533;z = -42.000001; This Solid mass = 1998.9380995506447 Center of Solid: x = 0.000002;y = 244.471533;z = -137.999998; This Solid mass = 4.188790204786394 Center of Solid: x = -0.000000;y = 290.500000;z = -47.000000; This Solid mass = 951.8048002047907 Center of Solid: x = -0.000000;y = 290.500000;z = -56.794693; This Solid mass = 9196.595426332882 Center of Solid: x = 35.652961;y = 189.204163;z = -62.957503; This Solid mass = 14.137166941154069 Center of Solid: x = 47.994656;y = 189.204163;z = -52.963397; This Solid mass = 3131.1503837897526 Center of Solid: x = 0.000000;y = 106.500000;z = -90.000000; This Solid mass = 12743.227021776174 Center of Solid: x = -0.000000;y = 139.414294;z = -90.000000; This Solid mass = 5046.897424302504 Center of Solid: x = -0.000004;y = 178.999999;z = -89.999996; This Solid mass = 2377.662039991875 Center of Solid: x = -0.000000;y = 166.750000;z = -90.000000; This Solid mass = 2377.662039991875 Center of Solid: x = 0.000000;y = 158.250000;z = -90.000000; This Solid mass = 2377.6620399918756 Center of Solid: x = -0.000000;y = 191.250000;z = -90.000000; This Solid mass = 2377.662039991875 Center of Solid: x = -0.000000;y = 199.750000;z = -90.000000; This Solid mass = 4813.889207068303 Center of Solid: x = 48.000000;y = 131.400017;z = -37.999999; This Solid mass = 4813.889207068301 Center of Solid: x = -48.000000;y = 131.400017;z = -38.000001; This Solid mass = 4813.889207068301 Center of Solid: x = 48.000000;y = 131.400017;z = -142.000001; This Solid mass = 4813.889207068301 Center of Solid: x = -48.000000;y = 131.400017;z = -142.000001; This Solid mass = 4813.889207068302 Center of Solid: x = 48.000000;y = 78.599983;z = -141.999999; This Solid mass = 4813.889207068303 Center of Solid: x = 48.000000;y = 78.599983;z = -37.999999; This Solid mass = 4813.889207068305 Center of Solid: x = -48.000000;y = 78.599983;z = -141.999999; This Solid mass = 4813.889207068301 Center of Solid: x = -48.000001;y = 78.599983;z = -37.999999; This Solid mass = 16082.638427578428 Center of Solid: x = 48.000000;y = 105.372204;z = -38.000000; This Solid mass = 16082.638427578428 Center of Solid: x = -48.000000;y = 105.372204;z = -38.000000; This Solid mass = 16082.638427578428 Center of Solid: x = 48.000000;y = 105.372204;z = -142.000000; This Solid mass = 16082.638427578413 Center of Solid: x = -48.000000;y = 105.372204;z = -142.000000; 零件数目为:44

该零件数目统计结果与用solidworks等商业软件导入文件时的结果一致。 在这里插入图片描述

下面要做爆炸图展示,想法是根据各个零件形心所在位置按照不同方向比例做平移。

import sys import time from math import pi import random from OCC.Core.gp import gp_Ax1, gp_Pnt, gp_Dir, gp_Trsf ,gp_Vec # 引入Occ模型几何尺寸元素模块,零件移动关键模块 from OCC.Core.TopLoc import TopLoc_Location # 引入Occ模型定位模块 from PyQt5.QtWidgets import QMainWindow, QAction, qApp, QApplication from SelfMadeQTviewer3D import qtViewer3d # 引入自己修改后的Occ3维模型展示模块 from OCC.Extend.DataExchange import read_step_file#STEP文件导入模块 from OCC.Extend.TopologyUtils import TopologyExplorer#STEP文件导入模块后的拓扑几何分析模块 from OCC.Core.Quantity import Quantity_Color, Quantity_TOC_RGB from OCC.Core.GProp import GProp_GProps#几何模型属性 from OCC.Core.BRepGProp import brepgprop_VolumeProperties#solid几何模型属性 class Example(QMainWindow): def __init__(self): super().__init__() self.canva = qtViewer3d(self) self.initUI() def initUI(self): exitAct = QAction('&Exit', self) exitAct.setShortcut('Ctrl+Q') exitAct.setStatusTip('Exit application') exitAct.triggered.connect(qApp.quit) self.statusBar() menubar = self.menuBar() fileMenu = menubar.addMenu('&File') fileMenu.addAction(exitAct) self.setGeometry(100, 50, 1200, 900) self.setWindowTitle('PyOcc Packed In Pyqt5') self.setCentralWidget(self.canva) self.StepModelExplore() self.show() def STEP_shape(self): stpshp = read_step_file('GateValveAssembly.STEP')# 读取step文件 return TopologyExplorer(stpshp)# step文件模型解析 def StepModelExplore(self): self.canva._display.EraseAll() self.STEPshp = self.STEP_shape() i=0 for solid in self.STEPshp.solids(): i=i+1#用于统计零件数目 props = GProp_GProps()#获取几何属性查询函数 brepgprop_VolumeProperties(solid, props)#计算出当前solid的集合属性 #matrix_of_inertia = props.MatrixOfInertia()#当前solid的惯性矩 cog = props.CentreOfMass()#当前solid的形心 cog_x, cog_y, cog_z = cog.Coord() print("This Solid mass = %s" % props.Mass())#当前solid的体积 # print("Center of Solid: x = %f;y = %f;z = %f;" % (cog_x, cog_y, cog_z)) # ----------爆炸图展示载入的3维模型---------------------- T=gp_Trsf()#定义一个变换函数 T.SetTranslation(gp_Vec(5*cog_x,5*cog_y,10*cog_z))#将变换函数设置为沿着指定向量平移 loc=TopLoc_Location(T)#将变换函数重新定位到几何拓扑上 solid.Location(loc)#将该几何拓扑solid定位 # ----------爆炸图展示载入的3维模型---------------------- color = Quantity_Color(random.random(), random.random(),random.random(),Quantity_TOC_RGB) self.canva._display.DisplayColoredShape(solid, color) print("零件数目为:%d" % (i)) self.canva._display.FitAll() if __name__ == '__main__': app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_()) 2 Number of shapes: 2 This Solid mass = 1671588.029631332 This Solid mass = 20416.786227435936 This Solid mass = 20416.786227435958 This Solid mass = 539264.8949639023 This Solid mass = 54103.19372018658 This Solid mass = 18954.852646672913 This Solid mass = 338469.4612692211 This Solid mass = 5220.770297180713 This Solid mass = 49449.28479252284 This Solid mass = 39139.64044792523 This Solid mass = 106966.64358232789 This Solid mass = 4781.860167653959 This Solid mass = 1309.926227762865 This Solid mass = 12662.473567635041 This Solid mass = 4781.860167653957 This Solid mass = 1309.9262277628643 This Solid mass = 12662.473567635043 This Solid mass = 36769.10249043011 This Solid mass = 10777.165686221655 This Solid mass = 1998.9380995506442 This Solid mass = 1998.9380995506447 This Solid mass = 4.188790204786394 This Solid mass = 951.8048002047907 This Solid mass = 9196.595426332882 This Solid mass = 14.137166941154069 This Solid mass = 3131.1503837897526 This Solid mass = 12743.227021776174 This Solid mass = 5046.897424302504 This Solid mass = 2377.662039991875 This Solid mass = 2377.662039991875 This Solid mass = 2377.6620399918756 This Solid mass = 2377.662039991875 This Solid mass = 4813.889207068303 This Solid mass = 4813.889207068301 This Solid mass = 4813.889207068301 This Solid mass = 4813.889207068301 This Solid mass = 4813.889207068302 This Solid mass = 4813.889207068303 This Solid mass = 4813.889207068305 This Solid mass = 4813.889207068301 This Solid mass = 16082.638427578428 This Solid mass = 16082.638427578428 This Solid mass = 16082.638427578428 This Solid mass = 16082.638427578413 零件数目为:44

最终爆炸图结果如下所示: 在这里插入图片描述

实际上,经过深入理解step文件内容,可以实现每一个零件的特征认定(比如step文件中颜色、材料、体积等),并实现对任意零件的操作(平移、旋转、删除) SelfMadeQTviewer3D.py文件内容如下:

import ctypes import logging import os import sys from OCC.Display import OCCViewer from PyQt5 import QtCore, QtGui, QtOpenGL, QtWidgets # check if signal available, not available # on PySide HAVE_PYQT_SIGNAL = hasattr(QtCore, 'pyqtSignal') logging.basicConfig(stream=sys.stdout, level=logging.DEBUG) log = logging.getLogger(__name__) class qtBaseViewer(QtOpenGL.QGLWidget): ''' The base Qt Widget for an OCC viewer ''' def __init__(self, parent=None): super(qtBaseViewer, self).__init__(parent) self._display = OCCViewer.Viewer3d() self._inited = False # enable Mouse Tracking self.setMouseTracking(True) # Strong focus self.setFocusPolicy(QtCore.Qt.WheelFocus) self.setAttribute(QtCore.Qt.WA_NativeWindow) self.setAttribute(QtCore.Qt.WA_PaintOnScreen) self.setAttribute(QtCore.Qt.WA_NoSystemBackground) self.setAutoFillBackground(False) def GetHandle(self): ''' returns an the identifier of the GUI widget. It must be an integer ''' win_id = self.winId() # this returns either an int or voitptr if "%s" % type(win_id) == "": # PySide ### with PySide, self.winId() does not return an integer if sys.platform == "win32": ## Be careful, this hack is py27 specific ## does not work with python31 or higher ## since the PyCObject api was changed ctypes.pythonapi.PyCObject_AsVoidPtr.restype = ctypes.c_void_p ctypes.pythonapi.PyCObject_AsVoidPtr.argtypes = [ctypes.py_object] win_id = ctypes.pythonapi.PyCObject_AsVoidPtr(win_id) elif not isinstance(win_id, int): # PyQt4 or 5 ## below integer cast may be required because self.winId() can ## returns a sip.voitptr according to the PyQt version used ## as well as the python version win_id = int(win_id) return win_id def resizeEvent(self, event): super(qtBaseViewer, self).resizeEvent(event) self._display.View.MustBeResized() def paintEngine(self): return None class qtViewer3d(qtBaseViewer): # emit signal when selection is changed # is a list of TopoDS_* if HAVE_PYQT_SIGNAL: sig_topods_selected = QtCore.pyqtSignal(list) def __init__(self, *kargs): qtBaseViewer.__init__(self, *kargs) self.setObjectName("qt_viewer_3d") self._drawbox = False self._zoom_area = False self._select_area = False self._inited = False self._leftisdown = False self._middleisdown = False self._rightisdown = False self._selection = None self._drawtext = True self._qApp = QtWidgets.QApplication.instance() self._key_map = {} self._current_cursor = "arrow" self._available_cursors = {} @property def qApp(self): # reference to QApplication instance return self._qApp @qApp.setter def qApp(self, value): self._qApp = value def InitDriver(self): self._display.Create(window_handle=self.GetHandle(), parent=self) # background gradient self._display.SetModeShaded() self._inited = True # dict mapping keys to functions self._key_map = {ord('W'): self._display.SetModeWireFrame, ord('S'): self._display.SetModeShaded, ord('A'): self._display.EnableAntiAliasing, ord('B'): self._display.DisableAntiAliasing, ord('H'): self._display.SetModeHLR, ord('F'): self._display.FitAll, ord('G'): self._display.SetSelectionMode} self.createCursors() def createCursors(self): module_pth = os.path.abspath(os.path.dirname(__file__)) icon_pth = os.path.join(module_pth, "icons") _CURSOR_PIX_ROT = QtGui.QPixmap(os.path.join(icon_pth, "cursor-rotate.png")) _CURSOR_PIX_PAN = QtGui.QPixmap(os.path.join(icon_pth, "cursor-pan.png")) _CURSOR_PIX_ZOOM = QtGui.QPixmap(os.path.join(icon_pth, "cursor-magnify.png")) _CURSOR_PIX_ZOOM_AREA = QtGui.QPixmap(os.path.join(icon_pth, "cursor-magnify-area.png")) self._available_cursors = { "arrow": QtGui.QCursor(QtCore.Qt.ArrowCursor), # default "pan": QtGui.QCursor(_CURSOR_PIX_PAN), "rotate": QtGui.QCursor(_CURSOR_PIX_ROT), "zoom": QtGui.QCursor(_CURSOR_PIX_ZOOM), "zoom-area": QtGui.QCursor(_CURSOR_PIX_ZOOM_AREA), } self._current_cursor = "arrow" def keyPressEvent(self, event): code = event.key() if code in self._key_map: self._key_map[code]() elif code in range(256): log.info('key: "%s"(code %i) not mapped to any function' % (chr(code), code)) else: log.info('key: code %i not mapped to any function' % code) def focusInEvent(self, event): if self._inited: self._display.Repaint() def focusOutEvent(self, event): if self._inited: self._display.Repaint() def paintEvent(self, event): if not self._inited: self.InitDriver() self._display.Context.UpdateCurrentViewer() if self._drawbox: painter = QtGui.QPainter(self) painter.setPen(QtGui.QPen(QtGui.QColor(0, 0, 0), 2)) rect = QtCore.QRect(*self._drawbox) painter.drawRect(rect) def wheelEvent(self, event): try: # PyQt4/PySide delta = event.delta() except: # PyQt5 delta = event.angleDelta().y() if delta > 0: zoom_factor = 2. else: zoom_factor = 0.5 self._display.ZoomFactor(zoom_factor) @property def cursor(self): return self._current_cursor @cursor.setter def cursor(self, value): if not self._current_cursor == value: self._current_cursor = value cursor = self._available_cursors.get(value) if cursor: self.qApp.setOverrideCursor(cursor) else: self.qApp.restoreOverrideCursor() def mousePressEvent(self, event): self.setFocus() ev = event.pos() self.dragStartPosX = ev.x() self.dragStartPosY = ev.y() self._display.StartRotation(self.dragStartPosX, self.dragStartPosY) def mouseReleaseEvent(self, event): pt = event.pos() modifiers = event.modifiers() if event.button() == QtCore.Qt.LeftButton: if self._select_area: [Xmin, Ymin, dx, dy] = self._drawbox self._display.SelectArea(Xmin, Ymin, Xmin + dx, Ymin + dy) self._select_area = False else: # multiple select if shift is pressed if modifiers == QtCore.Qt.ShiftModifier: self._display.ShiftSelect(pt.x(), pt.y()) else: # single select otherwise self._display.Select(pt.x(), pt.y()) if (self._display.selected_shapes is not None) and HAVE_PYQT_SIGNAL: self.sig_topods_selected.emit(self._display.selected_shapes) elif event.button() == QtCore.Qt.RightButton: if self._zoom_area: [Xmin, Ymin, dx, dy] = self._drawbox self._display.ZoomArea(Xmin, Ymin, Xmin + dx, Ymin + dy) self._zoom_area = False self.cursor = "arrow" def DrawBox(self, event): tolerance = 2 pt = event.pos() dx = pt.x() - self.dragStartPosX dy = pt.y() - self.dragStartPosY if abs(dx)


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3