def make_axis_triedron(self): self.x_axis = AIS_Axis( Geom_Line(gp_Lin(gp_Pnt(0, 0, 0), gp_Dir(gp_XYZ(1, 0, 0))))) self.y_axis = AIS_Axis( Geom_Line(gp_Lin(gp_Pnt(0, 0, 0), gp_Dir(gp_XYZ(0, 1, 0))))) self.z_axis = AIS_Axis( Geom_Line(gp_Lin(gp_Pnt(0, 0, 0), gp_Dir(gp_XYZ(0, 0, 1))))) self.x_axis.SetColor(Quantity_Color(1, 0, 0, Quantity_TOC_RGB)) self.y_axis.SetColor(Quantity_Color(0, 1, 0, Quantity_TOC_RGB)) self.z_axis.SetColor(Quantity_Color(0, 0, 1, Quantity_TOC_RGB))
def doscreen_impl(model, path, size, yaw=None, pitch=None, triedron=True): scn = Scene() try: mmm = model if isinstance(mmm, evalcache.LazyObject): mmm = mmm.unlazy() c = zencad.default_color() if REVERSE_COLOR: c = (c[2], c[1], c[0]) scn.add(mmm, c) except: for m in model: if isinstance(m, (tuple, list)): c = m[1] m = m[0] else: c = zencad.default_color() if REVERSE_COLOR: c = (c[2], c[1], c[0]) mod = m if isinstance(mod, evalcache.LazyObject): mod = mod.unlazy() if isinstance(mod, zencad.util.point3): c = Color(1, 0, 0) if REVERSE_COLOR: c = (c[2], c[1], c[0]) scn.add(mod, c) else: scn.add(mod, c) #viewer = scn.viewer # if triedron: # Always add triedron # viewer.set_triedron_axes() #view = viewer.create_view() # view.set_triedron(False) #view.set_virtual_window(size[0], size[1]) if yaw is None: yaw = math.pi * (7 / 16) + math.pi / 2 if pitch is None: pitch = math.pi * -0.15 render = OffscreenRenderer(path, size) for i in scn.interactives: render.Context.Display(i.ais_object, True) i.bind_context(render.Context) if triedron: x_axis = AIS_Axis( Geom_Line(gp_Lin(gp_Pnt(0, 0, 0), gp_Dir(gp_XYZ(1, 0, 0))))) y_axis = AIS_Axis( Geom_Line(gp_Lin(gp_Pnt(0, 0, 0), gp_Dir(gp_XYZ(0, 1, 0))))) z_axis = AIS_Axis( Geom_Line(gp_Lin(gp_Pnt(0, 0, 0), gp_Dir(gp_XYZ(0, 0, 1))))) x_axis.SetColor(Quantity_Color(1, 0, 0, Quantity_TOC_RGB)) y_axis.SetColor(Quantity_Color(0, 1, 0, Quantity_TOC_RGB)) z_axis.SetColor(Quantity_Color(0, 0, 1, Quantity_TOC_RGB)) render.Context.Display(x_axis, True) render.Context.Display(y_axis, True) render.Context.Display(z_axis, True) render.View.Camera().SetDirection(gp_Dir( math.cos(pitch) * math.cos(yaw), math.cos(pitch) * math.sin(yaw), math.sin(pitch), )) render.View.Camera().SetUp(gp_Dir(0, 0, 1)) render.View.FitAll(0.07) render.DoIt()
def show_axis(self, origin=(0, 0, 0), direction=(0, 0, 1)): ax_placement = Geom_Axis1Placement( gp_Ax1(gp_Pnt(*origin), gp_Dir(*direction))) ax = AIS_Axis(ax_placement) self._display_ais(ax)
def __init__(self, axis, color): self.axis = axis super().__init__(AIS_Axis(axis.to_Geom_Line()), color=color)
class DisplayWidget(BaseViewer): def __init__(self, axis_triedron=True, communicator=None): super().__init__() self.View = self._display.View self.Viewer = self._display.Viewer self.Context = self._display.Context self.init_driver_in_constructor = sys.platform == "win32" self._communicator = communicator self._orient = 1 self._drawbox = False self._zoom_area = False self._inited0 = False self._inited1 = False self._leftisdown = False self._middleisdown = False self._rightisdown = False self._drawtext = True self._perspective_mode = False self._first_shape = None self.mousedown = False self.keyboard_retranslate_mode = False self.tracking_mode = False self.last_redraw = time.time() self.animate_updated = threading.Event() self.reset_orient1() self.make_axis_triedron() if axis_triedron: self.enable_axis_triedron(True) self.camera_center_axes = ( AxisInteractiveObject(Axis(1, 0, 0), zencad.color.Color.red), AxisInteractiveObject(Axis(0, 1, 0), zencad.color.Color.green), AxisInteractiveObject(Axis(0, 0, 1), zencad.color.Color.blue) ) for iobj in self.camera_center_axes: self.Context.Display(iobj.ais_object, False) iobj.bind_context(self.Context) self.msphere = zencad.geom.solid._sphere(1) self.MarkerQController = ShapeInteractiveObject( self.msphere, color=zencad.color.Color(1, 0, 0)) self.MarkerWController = ShapeInteractiveObject( self.msphere, color=zencad.color.Color(0, 1, 0)) self.Context.Display(self.MarkerWController.ais_object, False) self.Context.Display(self.MarkerQController.ais_object, False) self.MarkerQController.bind_context(self.Context) self.MarkerWController.bind_context(self.Context) self.MarkerWController.hide(True) self.MarkerQController.hide(True) self.set_center_visible(False) if self.init_driver_in_constructor: self.InitDriver() def set_perspective(self, en): self._perspective_mode = en if en: self._display.View.Camera().SetProjectionType( Graphic3d_Camera.Projection_Perspective) else: self._display.View.Camera().SetProjectionType( Graphic3d_Camera.Projection_Orthographic) self.redraw() def reset_orient1(self): self._orient = 1 self.yaw = STARTED_YAW self.pitch = STARTED_PITCH self.set_orient1() # self.set_orient1() # self.update_orient1_from_view() self.redraw() def reset_orient2(self): self._orient = 2 self.set_orient2() self.redraw() def reset_orient(self): self.reset_orient1() self.autoscale() self.redraw() def set_orient1(self): self._display.View.Camera().SetDirection(gp_Dir( math.cos(self.pitch) * math.cos(self.yaw), math.cos(self.pitch) * math.sin(self.yaw), math.sin(self.pitch) )) self._display.View.Camera().SetUp(gp_Dir(0, 0, 1)) def set_orient2(self): pass def update_orient1_from_view(self): """Read actual camera orientation data from view""" d = self._display.View.Camera().Direction() x, y, z = d.X(), d.Y(), d.Z() self.pitch = math.asin(z) x = x / math.cos(self.pitch) y = y / math.cos(self.pitch) self.yaw = math.atan2(y, x) def set_orthogonal(self): self._display.View.Camera().SetUp(gp_Dir(0, 0, 1)) def eye(self): return point3(self._display.View.Eye()) def set_eye(self, pnt, orthogonal=True, redraw=False): self._display.View.Camera().SetEye(gp_Pnt(pnt.x, pnt.y, pnt.z)) if orthogonal: self.set_orthogonal() self.update_orient1_from_view() self.set_orient1() if redraw: self.redraw() def set_center_visible(self, en): if en: # self.camera_center_mark.hide(False) self.camera_center_axes[0].hide(False) self.camera_center_axes[1].hide(False) self.camera_center_axes[2].hide(False) else: # self.camera_center_mark.hide(True) self.camera_center_axes[0].hide(True) self.camera_center_axes[1].hide(True) self.camera_center_axes[2].hide(True) self.redraw() def set_center(self, pnt, redraw=True): self._display.View.Camera().SetCenter(to_Pnt(pnt)) self.set_orient1() if redraw: self.redraw() def center(self): return point3(self._display.View.Camera().Center()) def scale(self): return self._display.View.Camera().Scale() def set_scale(self, scl): return self._display.View.Camera().SetScale(scl) def centering(self): self.set_center(point3(0, 0, 0)) def make_axis_triedron(self): self.x_axis = AIS_Axis( Geom_Line(gp_Lin(gp_Pnt(0, 0, 0), gp_Dir(gp_XYZ(1, 0, 0))))) self.y_axis = AIS_Axis( Geom_Line(gp_Lin(gp_Pnt(0, 0, 0), gp_Dir(gp_XYZ(0, 1, 0))))) self.z_axis = AIS_Axis( Geom_Line(gp_Lin(gp_Pnt(0, 0, 0), gp_Dir(gp_XYZ(0, 0, 1))))) self.x_axis.SetColor(Quantity_Color(1, 0, 0, Quantity_TOC_RGB)) self.y_axis.SetColor(Quantity_Color(0, 1, 0, Quantity_TOC_RGB)) self.z_axis.SetColor(Quantity_Color(0, 0, 1, Quantity_TOC_RGB)) def attach_scene(self, scene): scene.display = self box = scene.boundbox() self.scene_max0 = max(box.xlength(), box.ylength(), box.zlength()) if self._first_shape is None: for iobj in scene.interactives: if isinstance(iobj, ShapeInteractiveObject): self._first_shape = iobj.shape break for iobj in scene.interactives: self.Context.Display(iobj.ais_object, False) iobj.bind_context(self.Context) self.autoscale() def remove_all(self): self._display.Context.RemoveAll(True) def display_interactive_object(self, iobj): self.Context.Display(iobj.ais_object, False) iobj.bind_context(self.Context) def autoscale(self, koeff=0.07): self.View.FitAll(koeff) self.View.Redraw() def enable_axis_triedron(self, en): if en: self.Context.Display(self.x_axis, True) self.Context.Display(self.y_axis, True) self.Context.Display(self.z_axis, True) else: self.Context.Erase(self.x_axis, True) self.Context.Erase(self.y_axis, True) self.Context.Erase(self.z_axis, True) def restore_location(self, dct): scale = dct["scale"] eye = point3(dct["eye"]) center = point3(dct["center"]) self.set_center(center) self.set_eye(eye) self.set_scale(scale) self.redraw() self.update_orient1_from_view() self.location_changed_handle() def store_location(self): return { "scale": self.scale(), "eye": self.eye().to_tuple(), "center": self.center().to_tuple() } def location_changed_handle(self): for c in self.camera_center_axes: c.relocate(zencad.geom.trans.translate(self.center())) if self._communicator: loc = self.store_location() self._communicator.send({"cmd": "location", "loc": loc}) def InitDriver(self): self._display.Create(window_handle=int(self.winId()), parent=self) self.Viewer.SetDefaultLights() self.Viewer.SetLightOn() self.Context.SetDisplayMode(AIS_Shaded, False) self.autoscale() self.MarkerWController.hide(True) self.MarkerQController.hide(True) def redraw_marker(self, qw, x, y, z): if qw == "q": marker = self.MarkerQController elif qw == "w": marker = self.MarkerWController marker.relocate(zencad.translate(x, y, z)) marker.hide(x == 0 and y == 0 and z == 0) self.redraw() def markerQPressed(self): self.marker1 = self.intersect_point( self.lastPosition[0], self.lastPosition[1] ) x = self.marker1[0].x y = self.marker1[0].y z = self.marker1[0].z if self._communicator: self._communicator.send({ "cmd": "qmarker", "x": x, "y": y, "z": z}) self.redraw_marker("q", x, y, z) def markerWPressed(self): self.marker2 = self.intersect_point( self.lastPosition[0], self.lastPosition[1] ) x = self.marker2[0].x y = self.marker2[0].y z = self.marker2[0].z if self._communicator: self._communicator.send({ "cmd": "wmarker", "x": x, "y": y, "z": z}) self.redraw_marker("w", x, y, z) def keyPressEvent(self, event): MOVE_SCALE = 0.03 modifiers = event.modifiers() # QApplication.keyboardModifiers() if event.key() == QtCore.Qt.Key_F3: self.markerQPressed() return elif event.key() == QtCore.Qt.Key_F4: self.markerWPressed() return elif event.key() == QtCore.Qt.Key_F5: self.move_forw(MOVE_SCALE) return elif event.key() == QtCore.Qt.Key_F6: self.move_back(MOVE_SCALE) return elif event.key() == QtCore.Qt.Key_F8: self.autoscale() return elif event.key() == QtCore.Qt.Key_PageUp: self.zoom_up() return elif event.key() == QtCore.Qt.Key_PageDown: self.zoom_down() return elif event.key() == QtCore.Qt.Key_W and (self.mousedown or self.keyboard_retranslate_mode is False): self.move_forw(MOVE_SCALE) return elif event.key() == QtCore.Qt.Key_S and (self.mousedown or self.keyboard_retranslate_mode is False): self.move_back(MOVE_SCALE) return elif event.key() == QtCore.Qt.Key_D and (self.mousedown or self.keyboard_retranslate_mode is False): self.move_right(MOVE_SCALE) return elif event.key() == QtCore.Qt.Key_A and (self.mousedown or self.keyboard_retranslate_mode is False): self.move_left(MOVE_SCALE) return elif event.key() == QtCore.Qt.Key_Alt: self.temporary1 = self.mapFromGlobal(QtGui.QCursor.pos()) return elif event.key() == QtCore.Qt.Key_Shift: ev = self.mapFromGlobal(QtGui.QCursor.pos()) self.dragStartPosX = ev.x() self.dragStartPosY = ev.y() return # If signal not handling here, translate it onto top level if self._communicator: self._communicator.send({ "cmd": "keypressed_raw", "key": event.key(), "modifiers": "", "text": event.text()}) def zoom_factor(self, factor): self._display.ZoomFactor(factor) def zoom_up(self): self.zoom_factor(1.07) def zoom_down(self): self.zoom_factor(1/1.07) def focusInEvent(self, event): if self._inited1: self._display.Repaint() def focusOutEvent(self, event): if self._inited1: self._display.Repaint() def showEvent(self, event): if not self._inited0: self._inited0 = True if not self.init_driver_in_constructor: self.InitDriver() def paintEvent(self, event): if not self._inited1: QtGui.QWindow.fromWinId(self.winId()).setFlags( QtGui.QWindow.fromWinId(self.winId()).flags() | QtCore.Qt.SubWindow) self._inited1 = True self._display.Context.UpdateCurrentViewer() def wheelEvent(self, event): mul = 1.1 delta = event.angleDelta().y() if delta > 0: zoom_factor = mul else: zoom_factor = 1/mul self._display.ZoomFactor(zoom_factor) self.location_changed_handle() def mousePressEvent(self, event): self.setFocus() ev = event.pos() self.dragStartPosX = ev.x() self.dragStartPosY = ev.y() self._display.StartRotation(self.dragStartPosX, self.dragStartPosY) self.temporary1 = event.pos() self.mousedown = True def mouseReleaseEvent(self, event): pt = event.pos() modifiers = event.modifiers() if event.button() == QtCore.Qt.LeftButton: pass 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.mousedown = False def redraw(self): self.animate_updated.clear() self._display.View.Redraw() self.last_redraw = time.time() self.animate_updated.set() def continuous_redraw(self): """Этот слот использует поток анимации для обновления виджета""" if time.time() - self.last_redraw > 0.012: self.redraw() else: self.animate_updated.set() def viewline(self, x, y): Xv, Yv, Zv, Vx, Vy, Vz = self.View.ConvertWithProj(x, y) return gp_Lin(gp_Pnt(Xv, Yv, Zv), gp_Dir(Vx, Vy, Vz)) def Select(self, X, Y): self.Context.MoveTo(X, Y, self.View, False) self.Context.Select(False) self.Context.InitSelected() self.selected_shapes = [] self.selected_ishapes = [] if self.Context.MoreSelected(): if self.Context.HasSelectedShape(): self.selected_shapes.append(self.Context.SelectedShape()) self.selected_ishapes.append( self.Context.SelectedInteractive()) # disable selection for prevent hilighting self.Context.ClearSelected(False) def intersect_point(self, x, y): self.Select(x, y) viewLine = self.viewline(x, y) for i in range(len(self.selected_shapes)): hShape = AIS_Shape.DownCast(self.selected_ishapes[i]) shape = hShape.Shape() loc = self.Context.Location(hShape) loc_shape = shape.Located(loc) shapeIntersector = IntCurvesFace_ShapeIntersector() shapeIntersector.Load(loc_shape, precision_Confusion()) shapeIntersector.Perform(viewLine, float("-inf"), float("+inf")) if shapeIntersector.NbPnt() >= 1: ip = shapeIntersector.Pnt(1) return point3(ip), True else: continue return point3(), False def mouseMoveEvent(self, evt): pt = evt.pos() buttons = int(evt.buttons()) modifiers = evt.modifiers() self.lastPosition = (evt.x(), evt.y()) if self.tracking_mode and not self.mousedown: ip, sts = self.intersect_point(evt.x(), evt.y()) if self._communicator: self._communicator.send({ "cmd": "trackinfo", "data": (ip.to_tuple(), sts) }) # ROTATE if (buttons == QtCore.Qt.LeftButton or modifiers == QtCore.Qt.AltModifier): if self._orient == 1: mv = evt.pos() - self.temporary1 self.temporary1 = evt.pos() self.yaw -= mv.x() * 0.01 self.pitch -= mv.y() * 0.01 if self.pitch > math.pi * 0.4999: self.pitch = math.pi * 0.4999 if self.pitch < -math.pi * 0.4999: self.pitch = -math.pi * 0.4999 self.set_orient1() self.continuous_redraw() elif self._orient == 2: self._display.Rotation(pt.x(), pt.y()) self.location_changed_handle() # DYNAMIC ZOOM elif (buttons == QtCore.Qt.MidButton): self._display.Repaint() self._display.DynamicZoom(abs(self.dragStartPosX), abs(self.dragStartPosY), abs(pt.x()), abs(pt.y())) self.dragStartPosX = pt.x() self.dragStartPosY = pt.y() self.location_changed_handle() # PAN elif (buttons == QtCore.Qt.RightButton or modifiers == QtCore.Qt.ShiftModifier): dx = pt.x() - self.dragStartPosX dy = pt.y() - self.dragStartPosY self.dragStartPosX = pt.x() self.dragStartPosY = pt.y() self._display.View.Pan(dx, -dy) self.location_changed_handle() def _resize_external(self, size): if self._inited0: self.resize(QtCore.QSize(*size)) def tracking_mode_enable(self, en): self.tracking_mode = en def external_communication_command(self, data): cmd = data["cmd"] try: if cmd == "autoscale": self.autoscale() elif cmd == "resetview": self.reset_orient() elif cmd == "redraw": self.redraw() elif cmd == "resize": self._resize_external(size=(data["size"][0], data["size"][1])) elif cmd == "orient1": self.reset_orient1() elif cmd == "orient2": self.reset_orient2() elif cmd == "centering": self.centering() elif cmd == "location": self.restore_location(data["loc"]) elif cmd == "set_perspective": self.set_perspective(data["en"]) elif cmd == "set_center_visible": self.set_center_visible(data["en"]) elif cmd == "first_person_mode": self.first_person_mode() elif cmd == "exportstl": self.addon_exportstl() elif cmd == "exportbrep": self.addon_exportbrep() elif cmd == "to_freecad": self.addon_to_freecad_action() elif cmd == "tracking": self.tracking_mode_enable(data["en"]) elif cmd == "keyboard_retranslate": self.keyboard_retranslate_mode = data["en"] elif cmd == "screenshot": self.addon_screenshot_upload() elif cmd == "save_screenshot": self.save_screenshot() elif cmd == "console": sys.stdout.write(data["data"]) except Exception as ex: print_to_stderr("Error on external command handling", repr(ex)) def move_vector_cross(self, vecin, koeff): vec = self.center() - self.eye() vec = vec.cross(vecin).normalize() * self.scene_max0 self.set_center(self.center() + vec * koeff, redraw=False) self.location_changed_handle() self.redraw() def move_vector_eye_line(self, koeff): vec = self.center() - self.eye() vecnorm = vec.normalize() * self.scene_max0 self.set_center(self.center() + vecnorm * koeff, redraw=False) self.set_eye(self.eye() + vecnorm * koeff, redraw=False) self.location_changed_handle() self.redraw() def move_back(self, koeff=1): self.move_vector_eye_line(-koeff) def move_forw(self, koeff=1): self.move_vector_eye_line(koeff) def move_left(self, koeff=1): self.move_vector_cross(vector3(0, 0, -1), koeff) def move_right(self, koeff=1): self.move_vector_cross(vector3(0, 0, 1), koeff) def first_person_mode(self): self.set_perspective(True) self.set_center(self.eye()-vector3(0, 0, 1), redraw=False) self.set_center_visible(False) self.set_orient1() self.redraw() def export_file_for_one_shape(self, filters, defaultFilter): # if self.scene.total() != 1 + self.count_of_helped_shapes: # print("more/less than one shape in scene:", self.scene.total() - self.count_of_helped_shapes) # return False, "", None shape = self._first_shape if shape is None: raise Exception("Display widget hasn't ShapeInteractiveObject") path = QtWidgets.QFileDialog.getSaveFileName( self, "STL Export", QtCore.QDir.currentPath(), filters, defaultFilter ) path = path[0] return True, path, shape def addon_exportstl(self): from zencad.convert.api import _to_stl ok, path, shape = self.export_file_for_one_shape( filters="*.stl;;*.*", defaultFilter="*.stl") if ok == False or path == "": return d, okPressed = QtWidgets.QInputDialog.getDouble( self, "Get double", "Value:", 0.01, 0, 10, 10 ) if not okPressed: return _to_stl(shape, path, d) print("Make STL procedure finished.") def addon_exportbrep(self): from zencad.convert.api import _to_brep ok, path, shape = self.export_file_for_one_shape( filters="*.brep;;*.*", defaultFilter="*.brep") if ok == False or path == "": return _to_brep(shape, path) print("Save BREP procedure finished.") def save_screenshot(self): filters = "*.png;;*.bmp;;*.jpg;;*.*" defaultFilter = "*.png" retpath = QtWidgets.QFileDialog.getSaveFileName( self, "Dump image", QtCore.QDir.currentPath(), filters, defaultFilter ) path = retpath[0] if path == "": return buf = glReadPixels(0, 0, self.width(), self.height(), GL_RGBA, GL_UNSIGNED_BYTE) pixmap = QtGui.QPixmap.fromImage(QtGui.QImage(buf, self.width(), self.height(), QtGui.QImage.Format_RGBA8888).mirrored(False, True)) file = QtCore.QFile(path) file.open(QtCore.QIODevice.WriteOnly) pixmap.save(file, "PNG") # self.screen_saver.set_background(self.last_screen) # self.openlock.unlock() def addon_to_freecad_action(self): from zencad.convert.api import _to_brep import tempfile # if self.scene.total() != 1 + self.count_of_helped_shapes: # print("more/less than one shape in scene:", self.scene.total() - self.count_of_helped_shapes) # return False, "", None tmpfl = tempfile.mktemp(".brep") cb = QtWidgets.QApplication.clipboard() cb.clear(mode=cb.Clipboard) cb.setText( 'import Part; export = Part.Shape(); export.read("{}"); Part.show(export); Gui.activeDocument().activeView().viewAxonometric(); Gui.SendMsgToActiveView("ViewFit")'.format( tmpfl ), mode=cb.Clipboard, ) _to_brep(self._first_shape, tmpfl) QtWidgets.QMessageBox.information( self, self.tr("ToFreeCad"), self.tr( "Script copied to clipboard. Don't close gui before script placing.") )