class AbstractNurbsObjectEditorView(QGLViewer): """ The class NurbsPatchEditor is the viewer of the scene, it contains all the informations about the NurbsPatch, that's why a getter and a setter have been created, the NubrsPatch is defined by a 2 dimensional Array of 3d Vectors""" Edit, Rotate = list(range(2)) valueChanged = pyqtSignal() manipulated = pyqtSignal() selectionChanged = pyqtSignal() def __init__(self, parent): """ Constructor :param parent: the parent widget """ QGLViewer.__init__(self, parent) self.setStateFileName('.nurbsobjecteditor.xml') self.mode = AbstractNurbsObjectEditorView.Edit # the nurbs patch self.nurbsObject = None # matrix of ctrl point manipulator self.ctrlPointManipulators = {} # shape and material to display the patch self.nurbsShape = Shape() self.defaultMaterial = Material((30, 200, 30), 1, transparency=0.5) self.nurbsShape.appearance = self.defaultMaterial # plantgl basic object to display nurbs self.discretizer = Discretizer() self.glrenderer = GLRenderer(self.discretizer) self.glrenderer.renderingMode = GLRenderer.Dynamic self.ctrlrenderer = GLCtrlPointRenderer(self.discretizer) self.bboxcomputer = BBoxComputer(self.discretizer) self.ctrlPointDisplay = None # Current selection self.selectionManipulator = None self.focus = None # rectangular selection self.selectionRect = False # for rectangular selection (with control) self.__rectangle = QRect() self.__rectangleInit = None self._drawNurbsObject = True self._drawGrid = True #creation of a default NurbsPatch self.setNurbsObject(self.newDefaultNurbsObject()) def getSelection(self): if self.selectionManipulator: return self.selectionManipulator.selection else: return [] def clear(self): """ clear current edition """ self.ctrlPointManipulators = {} self.clearSelectionManipulator() self.resetDisplay() def getCtrlPoints(self): return self.nurbsObject.ctrlPointMatrix def getCtrlPointsDim(self): return self.getCtrlPoints().sizes() def getCtrlPointManipulators(self): return self.ctrlPointManipulators def getBounds(self): """ Get the Bounding Box of the scene: return the minpos and maxpos that can be used by setSceneBoundingBox function""" self.nurbsObject.apply(self.bboxcomputer) res = self.bboxcomputer.result return Vec(*res.lowerLeftCorner), Vec(*res.upperRightCorner) def __propagate_valuechanged__(self, pid=None): """ emit a SIGNAL every time a value changed """ self.setSceneBoundingBox(*self.getBounds()) self.valueChanged.emit() self.resetDisplay() def resetDisplay(self, pid=None): self.ctrlPointDisplay = None def init(self): """ init function """ self.setSceneBoundingBox(*self.getBounds()) self.restoreStateFromFile() # init mouse interaction self.mode = AbstractNurbsObjectEditorView.Edit self.setInteractionMode(False) self.setMouseBindingDescription(Qt.ShiftModifier, Qt.LeftButton, "Rectangular selection") self.setMouseBindingDescription(Qt.NoModifier, Qt.LeftButton, "Camera/Control Points manipulation") self.setMouseBindingDescription( Qt.NoModifier, Qt.LeftButton, "When double clicking on a line, create a new line", True) self.setKeyDescription(Qt.Key_K, "Toggles control point wire display") self.setKeyDescription(Qt.Key_G, "Toggles patch display") def setFocus(self, point): """ Set focus to given control point """ if self.focus: self.focus.hasFocus = False self.focus = point if self.focus: point.hasFocus = True def clearSelectionManipulator(self): """ clear the selection manipulator """ if not self.selectionManipulator is None: self.selectionManipulator.clear() self.selectionManipulator.valueChanged.disconnect( self.__propagate_valuechanged__ ) # QObject.disconnect(self.selectionManipulator,SIGNAL("valueChanged()"),self.__propagate_valuechanged__) self.selectionManipulator = None self.resetDisplay() def createSelectionManipulator(self): """ ensure that the selection manipulator is existing and valid """ if not self.selectionManipulator: self.selectionManipulator = SelectionManipulator() self.selectionManipulator.valueChanged.connect( self.__propagate_valuechanged__ ) # QObject.connect(self.selectionManipulator,SIGNAL("valueChanged()"),self.__propagate_valuechanged__) self.resetDisplay() def mousePressEvent(self, event): """ Check for eventual operations the user asks: shift start rectangular selection else check for which point is selected """ #Rectangular selection if event.modifiers() == Qt.ShiftModifier: if event.button() == Qt.LeftButton: self.__rectangle = QRect(event.pos(), event.pos()) self.__rectangleInit = event.pos() self.selectionRect = True elif event.button() == Qt.RightButton: self.clearSelectionManipulator() self.selectionChanged.emit() self.updateGL() else: pointSelection = False if not self.selectionManipulator is None: pointSelection = self.selectionManipulator.checkIfAxisGrabsMouse( event, self) if not pointSelection: for cCtrlPoint in self.getCtrlPointManipulators().values(): cCtrlPoint.checkIfGrabsMouse(event.x(), event.y(), self.camera()) if cCtrlPoint.grabsMouse(): pointSelection = True self.setFocus(cCtrlPoint) if self.selectionManipulator and cCtrlPoint.selected: self.setManipulatedFrame(self.selectionManipulator) else: self.setManipulatedFrame(cCtrlPoint) break self.setInteractionMode(pointSelection) self.updateGL() QGLViewer.mousePressEvent(self, event) def setInteractionMode(self, frame=True): if frame: if self.mode != AbstractNurbsObjectEditorView.Edit: self.mode = AbstractNurbsObjectEditorView.Edit self.setMouseBinding(Qt.NoModifier, Qt.LeftButton, QGLViewer.FRAME, QGLViewer.TRANSLATE) self.setMouseBinding(Qt.NoModifier, Qt.RightButton, QGLViewer.FRAME, QGLViewer.NO_MOUSE_ACTION) self.setMouseBinding(Qt.ControlModifier, Qt.LeftButton, QGLViewer.CAMERA, QGLViewer.ROTATE) self.setMouseBinding(Qt.ControlModifier, Qt.RightButton, QGLViewer.CAMERA, QGLViewer.TRANSLATE) self.setMouseBinding(Qt.ControlModifier, Qt.MiddleButton, QGLViewer.CAMERA, QGLViewer.ZOOM) else: if self.mode != AbstractNurbsObjectEditorView.Rotate: self.mode = AbstractNurbsObjectEditorView.Rotate self.setMouseBinding(Qt.ControlModifier, Qt.LeftButton, QGLViewer.FRAME, QGLViewer.TRANSLATE) self.setMouseBinding(Qt.ControlModifier, Qt.RightButton, QGLViewer.FRAME, QGLViewer.NO_MOUSE_ACTION) self.setMouseBinding(Qt.NoModifier, Qt.LeftButton, QGLViewer.CAMERA, QGLViewer.ROTATE) self.setMouseBinding(Qt.NoModifier, Qt.RightButton, QGLViewer.CAMERA, QGLViewer.TRANSLATE) self.setMouseBinding(Qt.NoModifier, Qt.MiddleButton, QGLViewer.CAMERA, QGLViewer.ZOOM) def mouseDoubleClickEvent(self, event): """ mouseDoubleClickEvent: add a control point to the selection double clicking on it, empty the selection double clicking elsewhere """ if event.modifiers() & Qt.ShiftModifier: selection = False #Doubleclick on a control point add/delete it from the selection array# for cCtrlPoint in self.getCtrlPointManipulators().values(): cCtrlPoint.checkIfGrabsMouse(event.x(), event.y(), self.camera()) if cCtrlPoint.grabsMouse(): cCtrlPoint.selected = not cCtrlPoint.selected selection = True self.createSelectionManipulator() self.selectionManipulator.toogleSelection(cCtrlPoint) #Double click with shift anywhere but on a control point -> empty selection # if not selection: self.clearSelectionManipulator() self.selectionChanged.emit() else: ## Adding a column on the NurbsPatch# """ when double click on a line, the line is doubled """ self.select( event.pos() ) # select call drwWithName that render line of control points with ids selection = self.selectedName() if selection >= 0: selectedPoints = self.addElement(selection) if selectedPoints: self.createSelectionManipulator() for index in selectedPoints: self.selectionManipulator.add( self.ctrlPointManipulators[index]) else: self.clearSelectionManipulator() else: self.clearSelectionManipulator() self.selectionChanged.emit() def mouseMoveEvent(self, event): """ mouseMoveEvent """ #rectangular selection if self.selectionRect: self.__rectangle = QRect(self.__rectangleInit, event.pos()).normalized() self.updateGL() # by default camera or manipulated frame is manipulated QGLViewer.mouseMoveEvent(self, event) def mouseReleaseEvent(self, event): """On mouse release, we release every grabbed objects""" QGLViewer.mouseReleaseEvent(self, event) # clear manipulated object self.setManipulatedFrame(None) self.setFocus(None) if self.selectionManipulator: self.selectionManipulator.clearFocus() # end of rectangular selection : if self.selectionRect: self.selectionRect = False # Possibly swap left/right and top/bottom to make rectangle_ valid. self.__rectangle = QRect(self.__rectangleInit, event.pos()).normalized() # make rectangle with a minimal size if self.__rectangle.width() < 10 or self.__rectangle.height() < 10: self.__rectangle = QRect(event.pos().x() - 5, event.pos().y() - 5, 10, 10) self.selectionFromRect(self.__rectangle) self.setInteractionMode(False) self.updateGL() def selectionFromRect(self, rect): """ check if control point projections are in the given rectangle. If yes, put point in selection """ selectionOccur = False for cCtrlPoint in self.getCtrlPointManipulators().values(): point = self.camera().projectedCoordinatesOf(cCtrlPoint.position()) if (self.__rectangle.contains(int(point.x), int(point.y))): selectionOccur = True if not self.selectionManipulator: self.selectionManipulator = SelectionManipulator() self.selectionManipulator.valueChanged.connect( self.__propagate_valuechanged__ ) # QObject.connect(self.selectionManipulator,SIGNAL("valueChanged()"),self.__propagate_valuechanged__) self.selectionManipulator.toogleSelection(cCtrlPoint) if self.selectionManipulator and self.selectionManipulator.empty(): self.clearSelectionManipulator() self.ctrlPointDisplay = None if selectionOccur: self.selectionChanged.emit() def keyPressEvent(self, e): modifiers = e.modifiers() # A simple switch on e->key() is not sufficient if we want to take state key into account. # With a switch, it would have been impossible to separate 'F' from 'CTRL+F'. # That's why we use imbricated if...else and a "handled" boolean. if ((e.key() == Qt.Key_K) and (modifiers == Qt.NoModifier)): self._drawGrid = not self._drawGrid self.updateGL() elif (e.key() == Qt.Key_G) and (modifiers == Qt.NoModifier): self._drawNurbsObject = not self._drawNurbsObject self.updateGL() else: QGLViewer.keyPressEvent(self, e) def addElement(self, selection): nbcolumn = self.getCtrlPoints().getColumnNb() minp, maxp = self.getBounds() diff = norm(maxp - minp) / 20 if selection >= nbcolumn: row = selection - nbcolumn newpatch = addRowToPatch(self.nurbsObject, row, Vector4(diff, 0)) selectedPoints = [(row, i) for i in range(nbcolumn)] else: newpatch = addColumnToPatch(self.nurbsObject, selection, Vector4(diff, 0)) selectedPoints = [(i, selection) for i in range(self.getCtrlPoints().getRowNb())] self.setNurbsObject(newpatch) return selectedPoints def draw(self): """ Draw function : Control points of the nurbsPatch are represented by spheres. If some of them are selected, a medium axis will be drawn by lines and little spheres, allowing us to grab one of them to perform a constrained move """ ogl.glDisable(ogl.GL_LIGHTING) ogl.glPolygonMode(ogl.GL_FRONT_AND_BACK, ogl.GL_LINE) # draw the wire of the patch ogl.glLineWidth(1) if self._drawNurbsObject: self.drawNurbsObjectWire() if self._drawGrid: self.drawCtrlWire() # patch and control point shpere rendering ogl.glPolygonMode(ogl.GL_FRONT_AND_BACK, ogl.GL_FILL) ogl.glEnable(ogl.GL_LIGHTING) ogl.glLightModeli(ogl.GL_LIGHT_MODEL_TWO_SIDE, ogl.GL_TRUE) ogl.glEnable(ogl.GL_BLEND) ogl.glBlendFunc(ogl.GL_SRC_ALPHA, ogl.GL_ONE_MINUS_SRC_ALPHA) if self._drawNurbsObject: self.drawNurbsObject() self.drawCtrlPoints() ogl.glDisable(ogl.GL_BLEND) if self.selectionRect: # Draw rectangular selection self.startScreenCoordinatesSystem() # use screen coordinates r = self.__rectangle rect = Shape( Polyline2D([(r.x(), r.y()), (r.x() + r.width(), r.y()), (r.x() + r.width(), r.y() + r.height()), (r.x(), r.y() + r.height()), (r.x(), r.y())]), Material((200, 200, 200), 1)) ogl.glEnable(ogl.GL_LINE_STIPPLE) ogl.glLineStipple(1, 0x0FFF) ogl.glLineWidth(2) rect.apply(self.glrenderer) ogl.glDisable(ogl.GL_LINE_STIPPLE) self.stopScreenCoordinatesSystem() ogl.glLineWidth(1) def drawCtrlPoints(self): if self.ctrlPointDisplay is None: scradius = self.sceneRadius() pointsize = scradius / 30. shapes = [] #define the nurbsShape and the control points geometry for ctrlPoint in self.getCtrlPointManipulators().values(): shapes.append(ctrlPoint.representation(pointsize)) # draw the frame of multiple selection if self.selectionManipulator: shapes += self.selectionManipulator.representation(pointsize * 1.2) self.ctrlPointDisplay = Scene(shapes) # control point shpere rendering self.ctrlPointDisplay.apply(self.glrenderer) def drawCtrlWire(self): # ctrl line rendering Material((255, 255, 255), 1).apply(self.glrenderer) self.nurbsObject.apply(self.ctrlrenderer) def drawNurbsObject(self): sc = Scene([self.nurbsShape]) # patch rendering sc.apply(self.glrenderer) def drawNurbsObjectWire(self): shwire = Shape(self.nurbsObject, Material((120, 255, 0), 0.8)) shwire.apply(self.glrenderer) def drawWithNames(self): """ draw control lines with names """ pointmatrix = self.getCtrlPoints() lines = [] m = Material() maxcolumn = pointmatrix.getColumnNb() for colid in range(maxcolumn): lines.append( Shape( Polyline(Point4Array( pointmatrix.getColumn(colid)).project(), width=3), m, colid)) for rowid in range(pointmatrix.getRowNb()): lines.append( Shape( Polyline(Point4Array(pointmatrix.getRow(rowid)).project(), width=3), m, maxcolumn + rowid)) for sh in lines: ogl.glPushName(sh.id) sh.apply(self.glrenderer) ogl.glPopName() def getNurbsObject(self): """ return the edited nurbs patch """ return self.nurbsObject def setNurbsObject(self, nurbsObject): """ set the nurbs patch to edit """ self.clear() self.nurbsObject = nurbsObject self.setNurbsObjectView() self.setControlPointManipulators() def setControlPointManipulators(self): import itertools dims = list(map(float, self.getCtrlPointsDim())) def color(idx): try: r = 30 + int(220 * idx[0] / dims[0]) g = 30 + int(220 * idx[1] / dims[1]) if len(dims) > 1 else 250 b = 30 + int(220 * idx[2] / dims[2]) if len(dims) > 2 else 250 except: r = 250 g = 30 + int(220 * idx / dims[0]) b = 250 return (r, g, b) ctrlpoints = self.getCtrlPoints() self.ctrlPointManipulators = {} dims = self.getCtrlPointsDim() if len(dims) == 1: idxiter = list(range(dims[0])) else: idxiter = itertools.product(*[list(range(d)) for d in dims]) for pid, index in enumerate(idxiter): ctrlPoint = CtrlPoint(ctrlpoints[index], Pos4Setter(self.getCtrlPoints(), index, ctrlpoints[index].w), color=color(index), id=pid) ctrlPoint.setCallBack(self.__propagate_valuechanged__) self.ctrlPointManipulators[index] = ctrlPoint self.setSceneBoundingBox(*self.getBounds()) def setNurbsObjectView(self): self.nurbsShape.geometry = self.nurbsObject def helpString(self): return helpstr def closeEvent(self, event): """close the windows properly""" helpwidget = self.helpWidget() if helpwidget and helpwidget.isVisible(): helpwidget.hide() QGLViewer.closeEvent(self, event) def setUStride(self, value): self.nurbsObject.ustride = value self.valueChanged.emit() self.updateGL() def setWeigthToSelection(self, value): if self.selectionManipulator: try: if len(value) > 0: for v, p in zip(value, self.selectionManipulator.selection): p.position_setter.weight = v p.__propagate_position_change__() except: if abs(value) < 1e-3: return for p in self.selectionManipulator.selection: p.position_setter.weight = value p.__propagate_position_change__() self.updateGL()
class NurbsPatchEditor(QGLViewer): """ The class NurbsPatchEditor is the viewer of the scene, it contains all the informations about the NurbsPatch, that's why a getter and a setter have been created, the NubrsPatch is defined by a 2 dimensional Array of 3d Vectors""" Edit, Rotate = list(range(2)) valueChanged = pyqtSignal() def __init__(self, parent): """ Constructor :param parent: the parent widget """ QGLViewer.__init__(self, parent) self.setStateFileName('.nurbspatcheditor.xml') self.mode = NurbsPatchEditor.Edit # the nurbs patch self.nurbsPatch = None # matrix of ctrl point manipulator self.ctrlPointMatrix = [] # shape and material to display the patch self.nurbsShape = Shape() self.defaultMaterial = Material((30, 200, 30), 1, transparency=0.5) self.nurbsShape.appearance = self.defaultMaterial # plantgl basic object to display nurbs self.discretizer = Discretizer() self.glrenderer = GLRenderer(self.discretizer) self.glrenderer.renderingMode = GLRenderer.Dynamic self.ctrlrenderer = GLCtrlPointRenderer(self.discretizer) self.bboxcomputer = BBoxComputer(self.discretizer) # Current selection self.selectionManipulator = None self.focus = None # rectangular selection self.selectionRect = False # for rectangular selection (with control) self.__rectangle = QRect() self.__rectangleInit = None #creation of a default NurbsPatch if len(self.ctrlPointMatrix) == 0: self.setNurbsPatch(self.newDefaultNurbsPatch()) def __propagate_valuechanged__(self, pid=None): """ emit a SIGNAL every time a value changed """ self.setSceneBoundingBox(*self.getBounds()) self.valueChanged.emit( ) # self.emit(SIGNAL("valueChanged()")) # AUTO SIGNAL TRANSLATION def init(self): """ init function """ self.setSceneBoundingBox(*self.getBounds()) self.restoreStateFromFile() # init mouse interaction self.mode = NurbsPatchEditor.Edit self.setInteractionMode(False) self.setMouseBindingDescription(Qt.ShiftModifier + Qt.LeftButton, "Rectangular selection") self.setMouseBindingDescription(Qt.LeftButton, "Camera/Control Points manipulation") self.setMouseBindingDescription( Qt.LeftButton, "When double clicking on a line, create a new line", True) def getBounds(self): """ Get the Bounding Box of the scene: return the minpos and maxpos that can be used by setSceneBoundingBox function""" self.nurbsPatch.apply(self.bboxcomputer) res = self.bboxcomputer.result return Vec(*res.lowerLeftCorner), Vec(*res.upperRightCorner) def setFocus(self, point): """ Set focus to given control point """ if self.focus: self.focus.hasFocus = False self.focus = point if self.focus: point.hasFocus = True def clearSelectionManipulator(self): """ clear the selection manipulator """ if self.selectionManipulator: self.selectionManipulator.clear() self.selectionManipulator.valueChanged.disconnect( self.__propagate_valuechanged__ ) # QObject.disconnect(self.selectionManipulator,SIGNAL("valueChanged()"),self.__propagate_valuechanged__) self.selectionManipulator = None def createSelectionManipulator(self): """ ensure that the selection manipulator is existing and valid """ if not self.selectionManipulator: self.selectionManipulator = SelectionManipulator() self.selectionManipulator.valueChanged.connect( self.__propagate_valuechanged__ ) # QObject.connect(self.selectionManipulator,SIGNAL("valueChanged()"),self.__propagate_valuechanged__) def mousePressEvent(self, event): """ Check for eventual operations the user asks: shift start rectangular selection else check for which point is selected """ #Rectangular selection if event.modifiers() == Qt.ShiftModifier: if event.button() == Qt.LeftButton: self.__rectangle = QRect(event.pos(), event.pos()) self.__rectangleInit = event.pos() self.selectionRect = True elif event.button() == Qt.RightButton: self.clearSelectionManipulator() self.updateGL() else: pointSelection = False if self.selectionManipulator: pointSelection = self.selectionManipulator.checkIfAxisGrabsMouse( event, self) if not pointSelection: for ctrlPointRow in self.ctrlPointMatrix: for cCtrlPoint in ctrlPointRow: cCtrlPoint.checkIfGrabsMouse(event.x(), event.y(), self.camera()) if cCtrlPoint.grabsMouse(): pointSelection = True self.setFocus(cCtrlPoint) if self.selectionManipulator and cCtrlPoint.selected: self.setManipulatedFrame( self.selectionManipulator) else: self.setManipulatedFrame(cCtrlPoint) break self.setInteractionMode(pointSelection) self.updateGL() QGLViewer.mousePressEvent(self, event) def setInteractionMode(self, frame=True): if frame: if self.mode != NurbsPatchEditor.Edit: self.mode = NurbsPatchEditor.Edit self.setMouseBinding(Qt.LeftButton, QGLViewer.FRAME, QGLViewer.TRANSLATE) self.setMouseBinding(Qt.RightButton, QGLViewer.FRAME, QGLViewer.NO_MOUSE_ACTION) self.setMouseBinding(Qt.ControlModifier + Qt.LeftButton, QGLViewer.CAMERA, QGLViewer.ROTATE) self.setMouseBinding(Qt.ControlModifier + Qt.RightButton, QGLViewer.CAMERA, QGLViewer.TRANSLATE) self.setMouseBinding(Qt.ControlModifier + Qt.MiddleButton, QGLViewer.CAMERA, QGLViewer.ZOOM) else: if self.mode != NurbsPatchEditor.Rotate: self.mode = NurbsPatchEditor.Rotate self.setMouseBinding(Qt.ControlModifier + Qt.LeftButton, QGLViewer.FRAME, QGLViewer.TRANSLATE) self.setMouseBinding(Qt.ControlModifier + Qt.RightButton, QGLViewer.FRAME, QGLViewer.NO_MOUSE_ACTION) self.setMouseBinding(Qt.LeftButton, QGLViewer.CAMERA, QGLViewer.ROTATE) self.setMouseBinding(Qt.RightButton, QGLViewer.CAMERA, QGLViewer.TRANSLATE) self.setMouseBinding(Qt.MiddleButton, QGLViewer.CAMERA, QGLViewer.ZOOM) def mouseDoubleClickEvent(self, event): """ mouseDoubleClickEvent: add a control point to the selection double clicking on it, empty the selection double clicking elsewhere """ if event.modifiers() & Qt.ShiftModifier: selection = False #Doubleclick on a control point add/delete it from the selection array# for ctrlPointRow in self.ctrlPointMatrix: for cCtrlPoint in ctrlPointRow: cCtrlPoint.checkIfGrabsMouse(event.x(), event.y(), self.camera()) if cCtrlPoint.grabsMouse(): cCtrlPoint.selected = not cCtrlPoint.selected selection = True self.createSelectionManipulator() self.selectionManipulator.toogleSelection(cCtrlPoint) #Double click with shift anywhere but on a control point -> empty selection # if not selection: self.clearSelectionManipulator() else: ## Adding a column on the NurbsPatch# """ when double click on a line, the line is doubled """ self.select( event.pos() ) # select call drwWithName that render line of control points with ids selection = self.selectedName() if selection >= 0: nbcolumn = self.nurbsPatch.ctrlPointMatrix.getColumnNb() minp, maxp = self.getBounds() diff = norm(maxp - minp) / 20 if selection >= nbcolumn: row = selection - nbcolumn newpatch = addRowToPatch(self.nurbsPatch, row, Vector4(diff, 0)) selectedPoints = [(row, i) for i in range(nbcolumn)] else: newpatch = addColumnToPatch(self.nurbsPatch, selection, Vector4(diff, 0)) selectedPoints = [(i, selection) for i in range( self.nurbsPatch.ctrlPointMatrix.getRowNb())] self.setNurbsPatch(newpatch) self.createSelectionManipulator() for index in selectedPoints: self.selectionManipulator.add( self.ctrlPointMatrix[index[0]][index[1]]) else: self.clearSelectionManipulator() def mouseMoveEvent(self, event): """ mouseMoveEvent """ #rectangular selection if self.selectionRect: self.__rectangle = QRect(self.__rectangleInit, event.pos()).normalized() self.updateGL() # by default camera or manipulated frame is manipulated QGLViewer.mouseMoveEvent(self, event) def mouseReleaseEvent(self, event): """On mouse release, we release every grabbed objects""" QGLViewer.mouseReleaseEvent(self, event) # clear manipulated object self.setManipulatedFrame(None) self.setFocus(None) if self.selectionManipulator: self.selectionManipulator.clearFocus() # end of rectangular selection : if self.selectionRect: self.selectionRect = False # Possibly swap left/right and top/bottom to make rectangle_ valid. self.__rectangle = QRect(self.__rectangleInit, event.pos()).normalized() # make rectangle with a minimal size if self.__rectangle.width() < 10 or self.__rectangle.height() < 10: self.__rectangle = QRect(event.pos().x() - 5, event.pos().y() - 5, 10, 10) self.selectionFromRect(self.__rectangle) self.setInteractionMode(False) self.updateGL() def selectionFromRect(self, rect): """ check if control point projections are in the given rectangle. If yes, put point in selection """ for ctrlPointRow in self.ctrlPointMatrix: for cCtrlPoint in ctrlPointRow: point = self.camera().projectedCoordinatesOf( cCtrlPoint.position()) if (self.__rectangle.contains(point.x, point.y)): if not self.selectionManipulator: self.selectionManipulator = SelectionManipulator() self.selectionManipulator.valueChanged.connect( self.__propagate_valuechanged__ ) # QObject.connect(self.selectionManipulator,SIGNAL("valueChanged()"),self.__propagate_valuechanged__) self.selectionManipulator.toogleSelection(cCtrlPoint) if self.selectionManipulator and self.selectionManipulator.empty(): self.clearSelectionManipulator() def draw(self): """ Draw function : Control points of the nurbsPatch are represented by spheres. If some of them are selected, a medium axis will be drawn by lines and little spheres, allowing us to grab one of them to perform a constrained move """ scradius = self.sceneRadius() pointsize = scradius / 30. shapes = [] #define the nurbsShape and the control points geometry #self.p=[] for ctrlPointLine in self.ctrlPointMatrix: for ctrlPoint in ctrlPointLine: shapes.append(ctrlPoint.representation(pointsize)) # draw the frame of multiple selection if self.selectionManipulator: shapes += self.selectionManipulator.representation(pointsize * 1.2) shapes.append(self.nurbsShape) sc = Scene(shapes) ogl.glDisable(ogl.GL_LIGHTING) ogl.glPolygonMode(ogl.GL_FRONT_AND_BACK, ogl.GL_LINE) # draw the wire of the patch ogl.glLineWidth(1) shwire = Shape(self.nurbsPatch, Material((120, 255, 0), 0.8)) shwire.apply(self.glrenderer) # ctrl line rendering ogl.glLineWidth(1) Material((255, 255, 255), 1).apply(self.glrenderer) self.nurbsPatch.apply(self.ctrlrenderer) # patch and control point shpere rendering ogl.glPolygonMode(ogl.GL_FRONT_AND_BACK, ogl.GL_FILL) ogl.glEnable(ogl.GL_LIGHTING) ogl.glLightModeli(ogl.GL_LIGHT_MODEL_TWO_SIDE, ogl.GL_TRUE) ogl.glEnable(ogl.GL_BLEND) ogl.glBlendFunc(ogl.GL_SRC_ALPHA, ogl.GL_ONE_MINUS_SRC_ALPHA) sc.apply(self.glrenderer) ogl.glDisable(ogl.GL_BLEND) if self.selectionRect: # Draw rectangular selection self.startScreenCoordinatesSystem() # use screen coordinates r = self.__rectangle rect = Shape( Polyline2D([(r.x(), r.y()), (r.x() + r.width(), r.y()), (r.x() + r.width(), r.y() + r.height()), (r.x(), r.y() + r.height()), (r.x(), r.y())]), Material((200, 200, 200), 1)) ogl.glEnable(ogl.GL_LINE_STIPPLE) ogl.glLineStipple(1, 0x0FFF) ogl.glLineWidth(2) rect.apply(self.glrenderer) ogl.glDisable(ogl.GL_LINE_STIPPLE) self.stopScreenCoordinatesSystem() ogl.glLineWidth(1) def drawWithNames(self): """ draw control lines with names """ pointmatrix = self.nurbsPatch.ctrlPointMatrix lines = [] m = Material() maxcolumn = pointmatrix.getColumnNb() for colid in range(maxcolumn): lines.append( Shape( Polyline(Point4Array( pointmatrix.getColumn(colid)).project(), width=3), m, colid)) for rowid in range(pointmatrix.getRowNb()): lines.append( Shape( Polyline(Point4Array(pointmatrix.getRow(rowid)).project(), width=3), m, maxcolumn + rowid)) for sh in lines: ogl.glPushName(sh.id) sh.apply(self.glrenderer) ogl.glPopName() @staticmethod def newDefaultNurbsPatch(): """ return a default nurbs patch """ return NurbsPatch([[Vector4(j - 1.5, i - 1.5, 0, 1) for j in range(4)] for i in range(4)]) def getNurbsPatch(self): """ return the edited nurbs patch """ return self.nurbsPatch def setNurbsPatch(self, nurbsPatch): """ set the nurbs patch to edit """ self.clear() self.nurbsPatch = nurbsPatch self.nurbsShape.geometry = self.nurbsPatch nbLines = float(len(self.nurbsPatch.ctrlPointMatrix)) pid = 1 for j, linePoint in enumerate(self.nurbsPatch.ctrlPointMatrix): lineCtrlPoint = [] nbCols = len(linePoint) for i in range(nbCols): ctrlPoint = CtrlPoint(linePoint[i].project(), Pos4Setter( self.nurbsPatch.ctrlPointMatrix, (j, i)), color=(30 + int(220 * j / nbLines), 30 + int(220 * i / nbCols), 250), id=pid) pid += 1 ctrlPoint.setCallBack(self.__propagate_valuechanged__) lineCtrlPoint.append(ctrlPoint) self.ctrlPointMatrix.append(lineCtrlPoint) self.setSceneBoundingBox(*self.getBounds()) def clear(self): """ clear current edition """ self.ctrlPointMatrix = [] self.clearSelectionManipulator() def helpString(self): return helpstr def closeEvent(self, event): """close the windows properly""" helpwidget = self.helpWidget() if helpwidget and helpwidget.isVisible(): helpwidget.hide() QGLViewer.closeEvent(self, event)