def popup(self, pos=None, searchText=""): """ Popup the menu at `pos` (in screen coordinates). 'Search' text field is initialized with `searchText` if provided. """ if pos is None: pos = QPoint() self.__clearCurrentItems() self.__search.setText(searchText) patt = QRegExp("(^|\W)"+searchText) patt.setCaseSensitivity(False) self.__suggestPage.setFilterRegExp(patt) self.ensurePolished() if self.testAttribute(Qt.WA_Resized) and self.sizeGripEnabled(): size = self.size() else: size = self.sizeHint() desktop = QApplication.desktop() screen_geom = desktop.availableGeometry(pos) # Adjust the size to fit inside the screen. if size.height() > screen_geom.height(): size.setHeight(screen_geom.height()) if size.width() > screen_geom.width(): size.setWidth(screen_geom.width()) geom = QRect(pos, size) if geom.top() < screen_geom.top(): geom.setTop(screen_geom.top()) if geom.left() < screen_geom.left(): geom.setLeft(screen_geom.left()) bottom_margin = screen_geom.bottom() - geom.bottom() right_margin = screen_geom.right() - geom.right() if bottom_margin < 0: # Falls over the bottom of the screen, move it up. geom.translate(0, bottom_margin) # TODO: right to left locale if right_margin < 0: # Falls over the right screen edge, move the menu to the # other side of pos. geom.translate(-size.width(), 0) self.setGeometry(geom) self.show() if searchText: self.setFocusProxy(self.__search) else: self.setFocusProxy(None)
def popup(self, pos=None, searchText=""): """ Popup the menu at `pos` (in screen coordinates). 'Search' text field is initialized with `searchText` if provided. """ if pos is None: pos = QPoint() self.__clearCurrentItems() self.__search.setText(searchText) patt = QRegExp("(^|\W)" + searchText) patt.setCaseSensitivity(False) self.__suggestPage.setFilterRegExp(patt) self.ensurePolished() if self.testAttribute(Qt.WA_Resized) and self.sizeGripEnabled(): size = self.size() else: size = self.sizeHint() desktop = QApplication.desktop() screen_geom = desktop.availableGeometry(pos) # Adjust the size to fit inside the screen. if size.height() > screen_geom.height(): size.setHeight(screen_geom.height()) if size.width() > screen_geom.width(): size.setWidth(screen_geom.width()) geom = QRect(pos, size) if geom.top() < screen_geom.top(): geom.setTop(screen_geom.top()) if geom.left() < screen_geom.left(): geom.setLeft(screen_geom.left()) bottom_margin = screen_geom.bottom() - geom.bottom() right_margin = screen_geom.right() - geom.right() if bottom_margin < 0: # Falls over the bottom of the screen, move it up. geom.translate(0, bottom_margin) # TODO: right to left locale if right_margin < 0: # Falls over the right screen edge, move the menu to the # other side of pos. geom.translate(-size.width(), 0) self.setGeometry(geom) self.show() if searchText: self.setFocusProxy(self.__search) else: self.setFocusProxy(None)
def applyMargin(rect, margin): result = QRect(rect) result.setLeft(result.left()+margin) result.setRight(result.right()-margin) result.setTop(result.top()+margin) result.setBottom(result.bottom()-margin) return result
def calculateLogicalRect(self, physicalRect): gridX = self.parent().width() / 40 gridY = self.parent().height() / 30 logicalRect = QRect() logicalRect.setTop(round(physicalRect.top() / gridY)) logicalRect.setLeft(round(physicalRect.left() / gridX)) logicalRect.setWidth(round(physicalRect.width() / gridX)) logicalRect.setHeight(round(physicalRect.height() / gridY)) return logicalRect
def paint(self, painter, option, index): painter.setFont(option.font) painter.setBrush(QBrush(Qt.black)) if option.state & QStyle.State_Selected: painter.setPen(QPen(Qt.white)) rect = QRect(option.rect) rect.setLeft(rect.left() + 4) rect.setTop(rect.top() + 4) rect.setWidth(rect.width() - 8) rect.setHeight(rect.height() - 8) painter.drawText(rect, Qt.Horizontal | Qt.TextWordWrap, forceString(index.data()))
def paint(self, painter, option, index): self.initStyleOption(option, index) # No idea why, but this cast is required if we want to have access to the V4 valuess option = QStyleOptionViewItemV4(option) if (index.column() == 1) and (option.state & QStyle.State_Selected): cboption = QStyleOptionComboBox() cboption.rect = option.rect # On OS X (with Qt4.6.0), adding State_Enabled to the flags causes the whole drawing to # fail (draw nothing), but it's an OS X only glitch. On Windows, it works alright. cboption.state |= QStyle.State_Enabled QApplication.style().drawComplexControl(QStyle.CC_ComboBox, cboption, painter) painter.setBrush(option.palette.text()) rect = QRect(option.rect) rect.setLeft(rect.left()+4) painter.drawText(rect, Qt.AlignLeft, option.text) else: QStyledItemDelegate.paint(self, painter, option, index)
def paint(self, painter, option, index): self.initStyleOption(option, index) # No idea why, but this cast is required if we want to have access to the V4 valuess option = QStyleOptionViewItemV4(option) if (index.column() == 1) and (option.state & QStyle.State_Selected): cboption = QStyleOptionComboBox() cboption.rect = option.rect # On OS X (with Qt4.6.0), adding State_Enabled to the flags causes the whole drawing to # fail (draw nothing), but it's an OS X only glitch. On Windows, it works alright. cboption.state |= QStyle.State_Enabled QApplication.style().drawComplexControl(QStyle.CC_ComboBox, cboption, painter) painter.setBrush(option.palette.text()) rect = QRect(option.rect) rect.setLeft(rect.left() + 4) painter.drawText(rect, Qt.AlignLeft, option.text) else: QStyledItemDelegate.paint(self, painter, option, index)
def renderSplit(self, painter, rowStats, splitsRect): painter.setFont(self.ds.splitFont()) splitValues = [self.ds.splitValues(rowStats.index, i) for i in range(rowStats.splitCount)] colWidths = [0, 0, 0] for sv in splitValues: colWidths[0] = max(colWidths[0], self.stats.splitFM.width(sv.account)) colWidths[1] = max(colWidths[1], self.stats.splitFM.width(sv.memo)) colWidths[2] = max(colWidths[2], self.stats.splitFM.width(sv.amount)) top = splitsRect.top() for sv in splitValues: rect = QRect(splitsRect.left(), top, colWidths[0], self.stats.splitHeight) painter.drawText(rect, Qt.AlignLeft, sv.account) rect.setLeft(rect.right() + SPLIT_XPADDING) rect.setWidth(colWidths[1]) painter.drawText(rect, Qt.AlignLeft, sv.memo) rect.setLeft(rect.right() + SPLIT_XPADDING) rect.setWidth(colWidths[2]) painter.drawText(rect, Qt.AlignRight, sv.amount) top += self.stats.splitHeight
def widget_popup_geometry(pos, widget): widget.ensurePolished() if widget.testAttribute(Qt.WA_Resized): size = widget.size() else: size = widget.sizeHint() desktop = QApplication.desktop() screen_geom = desktop.availableGeometry(pos) # Adjust the size to fit inside the screen. if size.height() > screen_geom.height(): size.setHeight(screen_geom.height()) if size.width() > screen_geom.width(): size.setWidth(screen_geom.width()) geom = QRect(pos, size) if geom.top() < screen_geom.top(): geom.setTop(screen_geom.top()) if geom.left() < screen_geom.left(): geom.setLeft(screen_geom.left()) bottom_margin = screen_geom.bottom() - geom.bottom() right_margin = screen_geom.right() - geom.right() if bottom_margin < 0: # Falls over the bottom of the screen, move it up. geom.translate(0, bottom_margin) # TODO: right to left locale if right_margin < 0: # Falls over the right screen edge, move the menu to the # other side of pos. geom.translate(-size.width(), 0) return geom
class MincutConnec(QgsMapTool): canvasClicked = pyqtSignal() def __init__(self, iface, controller): """ Class constructor """ self.iface = iface self.canvas = self.iface.mapCanvas() self.controller = controller # Call superclass constructor and set current action QgsMapTool.__init__(self, self.canvas) self.dragging = False # Vertex marker color = QColor(255, 100, 255) self.vertex_marker = QgsVertexMarker(self.canvas) self.vertex_marker.setIconType(QgsVertexMarker.ICON_CIRCLE) self.vertex_marker.setColor(color) self.vertex_marker.setIconSize(15) self.vertex_marker.setPenWidth(3) # Rubber band self.rubber_band = QgsRubberBand(self.canvas, QGis.Line) self.rubber_band.setColor(color) self.rubber_band.setWidth(1) # Select rectangle self.select_rect = QRect() # TODO: Parametrize self.connec_group = ["Wjoin", "Tap", "Fountain", "Greentap"] #self.snapperManager = SnappingConfigManager(self.iface) self.snapper = QgsMapCanvasSnapper(self.canvas) def activate(self): pass def canvasPressEvent(self, event): #@UnusedVariable self.select_rect.setRect(0, 0, 0, 0) self.rubber_band.reset() def canvasMoveEvent(self, event): """ With left click the digitizing is finished """ if event.buttons() == Qt.LeftButton: if not self.dragging: self.dragging = True self.select_rect.setTopLeft(event.pos()) self.select_rect.setBottomRight(event.pos()) self.set_rubber_band() else: # Hide highlight self.vertex_marker.hide() # Get the click x = event.pos().x() y = event.pos().y() event_point = QPoint(x, y) # Snapping (retval, result) = self.snapper.snapToBackgroundLayers( event_point) # @UnusedVariable # That's the snapped point if result: # Check feature for snap_point in result: element_type = snap_point.layer.name() if element_type in self.connec_group: # Get the point point = QgsPoint(snap_point.snappedVertex) # Add marker self.vertex_marker.setCenter(point) self.vertex_marker.show() break def canvasReleaseEvent(self, event): """ With left click the digitizing is finished """ if event.button() == Qt.LeftButton: # Get the click x = event.pos().x() y = event.pos().y() event_point = QPoint(x, y) # Not dragging, just simple selection if not self.dragging: # Snap to node (retval, result) = self.snapper.snapToBackgroundLayers( event_point) # @UnusedVariable # That's the snapped point if result: # Check feature for snapped_point in result: element_type = snapped_point.layer.name() if element_type in self.connec_group: feat_type = 'connec' else: continue point = QgsPoint( snapped_point.snappedVertex) # @UnusedVariable # layer.removeSelection() # layer.select([result[0].snappedAtGeometry]) #snapped_point.layer.removeSelection() snapped_point.layer.select( [snapped_point.snappedAtGeometry]) else: # Set valid values for rectangle's width and height if self.select_rect.width() == 1: self.select_rect.setLeft(self.select_rect.left() + 1) if self.select_rect.height() == 1: self.select_rect.setBottom(self.select_rect.bottom() + 1) self.set_rubber_band() self.select_multiple_features(self.selected_rectangle) self.dragging = False # Refresh map canvas self.rubber_band.reset() self.refresh_map_canvas() def set_rubber_band(self): # Coordinates transform transform = self.canvas.getCoordinateTransform() # Coordinates ll = transform.toMapCoordinates(self.select_rect.left(), self.select_rect.bottom()) lr = transform.toMapCoordinates(self.select_rect.right(), self.select_rect.bottom()) ul = transform.toMapCoordinates(self.select_rect.left(), self.select_rect.top()) ur = transform.toMapCoordinates(self.select_rect.right(), self.select_rect.top()) # Rubber band self.rubber_band.reset() self.rubber_band.addPoint(ll, False) self.rubber_band.addPoint(lr, False) self.rubber_band.addPoint(ur, False) self.rubber_band.addPoint(ul, False) self.rubber_band.addPoint(ll, True) self.selected_rectangle = QgsRectangle(ll, ur) def select_multiple_features(self, rectangle): if self.connec_group is None: return if QGis.QGIS_VERSION_INT >= 21600: # Selection for all connec group layers for layer_name in self.connec_group: # Get layer by his name layer = self.controller.get_layer_by_layername(layer_name, log_info=True) if layer: self.group_pointers_connec.append(layer) layer.selectByRect(rectangle) else: for layer_name in self.connec_group: self.iface.setActiveLayer(layer) layer.removeSelection() layer.select(rectangle, True)
class BrushingModel(QObject): brushSizeChanged = pyqtSignal(int) brushColorChanged = pyqtSignal(QColor) brushStrokeAvailable = pyqtSignal(QPointF, object) drawnNumberChanged = pyqtSignal(int) minBrushSize = 1 maxBrushSize = 61 defaultBrushSize = 3 defaultDrawnNumber = 1 defaultColor = Qt.white erasingColor = Qt.black erasingNumber = 100 def __init__(self): QObject.__init__(self) self.sliceRect = None self.bb = QRect() #bounding box enclosing the drawing self.brushSize = self.defaultBrushSize self.drawColor = self.defaultColor self._temp_color = None self._temp_number = None self.drawnNumber = self.defaultDrawnNumber self.pos = None self.erasing = False self.drawOnto = None #an empty scene, where we add all drawn line segments #a QGraphicsLineItem, and which we can use to then #render to an image self.scene = QGraphicsScene() def toggleErase(self): self.erasing = not(self.erasing) if self.erasing: self.setErasing() else: self.disableErasing() def setErasing(self): self.erasing = True self._temp_color = self.drawColor self._temp_number = self.drawnNumber self.setBrushColor(self.erasingColor) self.brushColorChanged.emit(self.erasingColor) self.setDrawnNumber(self.erasingNumber) def disableErasing(self): self.erasing = False self.setBrushColor(self._temp_color) self.brushColorChanged.emit(self.drawColor) self.setDrawnNumber(self._temp_number) def setBrushSize(self, size): self.brushSize = size self.brushSizeChanged.emit(self.brushSize) def setDrawnNumber(self, num): print "Setting Drawnnumer", num self.drawnNumber = num self.drawnNumberChanged.emit(num) def getBrushSize(self): return self.brushSize def brushSmaller(self): b = self.brushSize if b > self.minBrushSize: self.setBrushSize(b-1) def brushBigger(self): b = self.brushSize if self.brushSize < self.maxBrushSize: self.setBrushSize(b+1) def setBrushColor(self, color): self.drawColor = color self.brushColorChanged.emit(self.drawColor) def beginDrawing(self, pos, sliceRect): self.sliceRect = sliceRect self.scene.clear() self.bb = QRect() self.pos = QPointF(pos.x()+0.0001, pos.y()+0.0001) line = self.moveTo(pos) return line def endDrawing(self, pos): self.moveTo(pos) tempi = QImage(QSize(self.bb.width(), self.bb.height()), QImage.Format_ARGB32_Premultiplied) #TODO: format tempi.fill(0) painter = QPainter(tempi) self.scene.render(painter, target=QRectF(), source=QRectF(QPointF(self.bb.x(), self.bb.y()), QSizeF(self.bb.width(), self.bb.height()))) painter.end() ndarr = qimage2ndarray.rgb_view(tempi)[:,:,0] labels = numpy.where(ndarr>0,numpy.uint8(self.drawnNumber),numpy.uint8(0)) labels = labels.swapaxes(0,1) assert labels.shape[0] == self.bb.width() assert labels.shape[1] == self.bb.height() self.brushStrokeAvailable.emit(QPointF(self.bb.x(), self.bb.y()), labels) def dumpDraw(self, pos): res = self.endDrawing(pos) self.beginDrawing(pos, self.sliceRect) return res def moveTo(self, pos): oldX, oldY = self.pos.x(), self.pos.y() x,y = pos.x(), pos.y() #print "BrushingModel.moveTo(pos=%r)" % (pos) line = QGraphicsLineItem(oldX, oldY, x, y) line.setPen(QPen( QBrush(Qt.white), self.brushSize, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) self.scene.addItem(line) #update bounding Box if not self.bb.isValid(): self.bb = QRect(QPoint(x,y), QSize(1,1)) #grow bounding box self.bb.setLeft( min(self.bb.left(), max(0, x-self.brushSize/2-1) ) ) self.bb.setRight( max(self.bb.right(), min(self.sliceRect[0]-1, x+self.brushSize/2+1) ) ) self.bb.setTop( min(self.bb.top(), max(0, y-self.brushSize/2-1) ) ) self.bb.setBottom(max(self.bb.bottom(), min(self.sliceRect[1]-1, y+self.brushSize/2+1) ) ) #update/move position self.pos = pos
class BrushingModel(QObject): brushSizeChanged = pyqtSignal(int) brushColorChanged = pyqtSignal(QColor) brushStrokeAvailable = pyqtSignal(QPointF, object) drawnNumberChanged = pyqtSignal(int) minBrushSize = 1 maxBrushSize = 61 defaultBrushSize = 3 defaultDrawnNumber = 1 defaultColor = Qt.white erasingColor = Qt.black erasingNumber = 100 def __init__(self, parent=None): QObject.__init__(self, parent=parent) self.sliceRect = None self.bb = QRect() #bounding box enclosing the drawing self.brushSize = self.defaultBrushSize self.drawColor = self.defaultColor self._temp_color = None self._temp_number = None self.drawnNumber = self.defaultDrawnNumber self.pos = None self.erasing = False self._hasMoved = False self.drawOnto = None #an empty scene, where we add all drawn line segments #a QGraphicsLineItem, and which we can use to then #render to an image self.scene = QGraphicsScene() def toggleErase(self): self.erasing = not (self.erasing) if self.erasing: self.setErasing() else: self.disableErasing() def setErasing(self): self.erasing = True self._temp_color = self.drawColor self._temp_number = self.drawnNumber self.setBrushColor(self.erasingColor) self.brushColorChanged.emit(self.erasingColor) self.setDrawnNumber(self.erasingNumber) def disableErasing(self): self.erasing = False self.setBrushColor(self._temp_color) self.brushColorChanged.emit(self.drawColor) self.setDrawnNumber(self._temp_number) def setBrushSize(self, size): self.brushSize = size self.brushSizeChanged.emit(self.brushSize) def setDrawnNumber(self, num): self.drawnNumber = num self.drawnNumberChanged.emit(num) def getBrushSize(self): return self.brushSize def brushSmaller(self): b = self.brushSize if b > self.minBrushSize: self.setBrushSize(b - 1) def brushBigger(self): b = self.brushSize if self.brushSize < self.maxBrushSize: self.setBrushSize(b + 1) def setBrushColor(self, color): self.drawColor = color self.brushColorChanged.emit(self.drawColor) def beginDrawing(self, pos, sliceRect): ''' pos -- QPointF-like ''' self.sliceRect = sliceRect self.scene.clear() self.bb = QRect() self.pos = QPointF(pos.x(), pos.y()) self._hasMoved = False def endDrawing(self, pos): has_moved = self._hasMoved # _hasMoved will change after calling moveTo if has_moved: self.moveTo(pos) else: assert (self.pos == pos) self.moveTo(QPointF(pos.x() + 0.0001, pos.y() + 0.0001)) # move a little # Qt seems to use strange rules for determining which pixels to set when rendering a brush stroke to a QImage. # We seem to get better results if we do the following: # 1) Slightly offset the source window because apparently there is a small shift in the data # 2) Render the scene to an image that is MUCH larger than the scene resolution (4x by 4x) # 3) Downsample each 4x4 patch from the large image back to a single pixel in the final image, # applying some threshold to determine if the final pixel is on or off. tempi = QImage(QSize(4 * self.bb.width(), 4 * self.bb.height()), QImage.Format_ARGB32_Premultiplied) #TODO: format tempi.fill(0) painter = QPainter(tempi) # Offset the source window. At first I thought the right offset was 0.5, because # that would seem to make sure points are rounded to pixel CENTERS, but # experimentation indicates that 0.25 is slightly better for some reason... source_rect = QRectF(QPointF(self.bb.x() + 0.25, self.bb.y() + 0.25), QSizeF(self.bb.width(), self.bb.height())) target_rect = QRectF(QPointF(0, 0), QSizeF(4 * self.bb.width(), 4 * self.bb.height())) self.scene.render(painter, target=target_rect, source=source_rect) painter.end() # Now downsample: convert each 4x4 patch into a single pixel by summing and dividing ndarr = qimage2ndarray.rgb_view(tempi)[:, :, 0].astype(int) ndarr = ndarr.reshape((ndarr.shape[0], ) + (ndarr.shape[1] // 4, ) + (4, )) ndarr = ndarr.sum(axis=-1) ndarr = ndarr.transpose() ndarr = ndarr.reshape((ndarr.shape[0], ) + (ndarr.shape[1] // 4, ) + (4, )) ndarr = ndarr.sum(axis=-1) ndarr = ndarr.transpose() ndarr //= 4 * 4 downsample_threshold = (7. / 16) * 255 labels = numpy.where(ndarr >= downsample_threshold, numpy.uint8(self.drawnNumber), numpy.uint8(0)) labels = labels.swapaxes(0, 1) assert labels.shape[0] == self.bb.width() assert labels.shape[1] == self.bb.height() ## ## ensure that at least one pixel is label when the brush size is 1 ## ## this happens when the user just clicked without moving ## in that case the lineitem will be so tiny, that it won't be rendered ## into a single pixel by the code above if not has_moved and self.brushSize <= 1 and numpy.count_nonzero( labels) == 0: labels[labels.shape[0] // 2, labels.shape[1] // 2] = self.drawnNumber self.brushStrokeAvailable.emit(QPointF(self.bb.x(), self.bb.y()), labels) def dumpDraw(self, pos): res = self.endDrawing(pos) self.beginDrawing(pos, self.sliceRect) return res def moveTo(self, pos): #data coordinates oldX, oldY = self.pos.x(), self.pos.y() x, y = pos.x(), pos.y() line = QGraphicsLineItem(oldX, oldY, x, y) line.setPen( QPen(QBrush(Qt.white), self.brushSize, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) self.scene.addItem(line) self._hasMoved = True #update bounding Box if not self.bb.isValid(): self.bb = QRect(QPoint(oldX, oldY), QSize(1, 1)) #grow bounding box self.bb.setLeft( min(self.bb.left(), max(0, x - self.brushSize // 2 - 1))) self.bb.setRight( max(self.bb.right(), min(self.sliceRect[0] - 1, x + self.brushSize // 2 + 1))) self.bb.setTop(min(self.bb.top(), max(0, y - self.brushSize // 2 - 1))) self.bb.setBottom( max(self.bb.bottom(), min(self.sliceRect[1] - 1, y + self.brushSize // 2 + 1))) #update/move position self.pos = pos
class ConnecMapTool(ParentMapTool): """ Button 20: User select connections from layer 'connec' Execute SQL function: 'gw_fct_connect_to_network' """ def __init__(self, iface, settings, action, index_action): """ Class constructor """ # Call ParentMapTool constructor super(ConnecMapTool, self).__init__(iface, settings, action, index_action) self.dragging = False # Select rectangle self.select_rect = QRect() """ QgsMapTools inherited event functions """ def canvasMoveEvent(self, event): """ With left click the digitizing is finished """ if event.buttons() == Qt.LeftButton: if not self.dragging: self.dragging = True self.select_rect.setTopLeft(event.pos()) self.select_rect.setBottomRight(event.pos()) self.set_rubber_band() else: # Hide marker self.vertex_marker.hide() # Get the click x = event.pos().x() y = event.pos().y() event_point = QPoint(x, y) # Snapping (retval, result) = self.snapper.snapToBackgroundLayers( event_point) # @UnusedVariable # That's the snapped features if result: for snapped_feat in result: # Check if it belongs to 'connec' or 'gully' group exist_connec = self.snapper_manager.check_connec_group( snapped_feat.layer) exist_gully = self.snapper_manager.check_gully_group( snapped_feat.layer) if exist_connec or exist_gully: # Get the point and add marker point = QgsPoint(result[0].snappedVertex) self.vertex_marker.setCenter(point) self.vertex_marker.show() break def canvasPressEvent(self, event): #@UnusedVariable self.select_rect.setRect(0, 0, 0, 0) self.rubber_band.reset(QGis.Polygon) def canvasReleaseEvent(self, event): """ With left click the digitizing is finished """ if event.button() == Qt.LeftButton: # Get the click x = event.pos().x() y = event.pos().y() event_point = QPoint(x, y) # Simple selection if not self.dragging: # Snap to connec or gully (retval, result) = self.snapper.snapToBackgroundLayers( event_point) # @UnusedVariable # That's the snapped features if result: # Check if it belongs to 'connec' or 'gully' group exist_connec = self.snapper_manager.check_connec_group( result[0].layer) exist_gully = self.snapper_manager.check_gully_group( result[0].layer) if exist_connec or exist_gully: key = QApplication.keyboardModifiers() # If Ctrl+Shift is clicked: deselect snapped feature if key == (Qt.ControlModifier | Qt.ShiftModifier): result[0].layer.deselect( [result[0].snappedAtGeometry]) else: # If Ctrl is not clicked: remove previous selection if key != Qt.ControlModifier: result[0].layer.removeSelection() result[0].layer.select( [result[0].snappedAtGeometry]) # Hide marker self.vertex_marker.hide() # Multiple selection else: # Set valid values for rectangle's width and height if self.select_rect.width() == 1: self.select_rect.setLeft(self.select_rect.left() + 1) if self.select_rect.height() == 1: self.select_rect.setBottom(self.select_rect.bottom() + 1) self.set_rubber_band() selected_geom = self.rubber_band.asGeometry() #@UnusedVariable self.select_multiple_features(self.selected_rectangle) self.dragging = False # Refresh map canvas self.rubber_band.reset() elif event.button() == Qt.RightButton: # Check selected records number_features = 0 for layer in self.layer_connec_man: number_features += layer.selectedFeatureCount() if number_features > 0: message = ("Number of features selected in the 'connec' group") title = "Interpolate value - Do you want to update values" answer = self.controller.ask_question( message, title, parameter=str(number_features)) if answer: # Create link self.link_selected_features('connec', self.layer_connec_man) if self.layer_gully_man: # Check selected records number_features = 0 for layer in self.layer_gully_man: number_features += layer.selectedFeatureCount() if number_features > 0: message = ( "Number of features selected in the 'gully' group") title = "Interpolate value - Do you want to update values" answer = self.controller.ask_question( message, title, parameter=str(number_features)) if answer: # Create link self.link_selected_features('gully', self.layer_gully_man) def activate(self): # Check button self.action().setChecked(True) # Rubber band self.rubber_band.reset() # Store user snapping configuration self.snapper_manager.store_snapping_options() # Clear snapping self.snapper_manager.clear_snapping() # Set snapping to 'connec' and 'gully' self.snapper_manager.snap_to_connec_gully() # Change cursor cursor = self.get_cursor_multiple_selection() self.canvas.setCursor(cursor) # Show help message when action is activated if self.show_help: message = "Right click to use current selection, select connec points by clicking or dragging (selection box)" self.controller.show_info(message) def deactivate(self): # Call parent method ParentMapTool.deactivate(self) def link_selected_features(self, geom_type, layers): """ Link selected @geom_type to the pipe """ # Check features selected number_features = 0 for layer in layers: number_features += layer.selectedFeatureCount() if number_features == 0: message = "You have to select at least one feature!" self.controller.show_warning(message) return # Get selected features from layers of selected @geom_type aux = "{" field_id = geom_type + "_id" # Iterate over all layers for layer in layers: if layer.selectedFeatureCount() > 0: # Get selected features of the layer features = layer.selectedFeatures() for feature in features: feature_id = feature.attribute(field_id) aux += str(feature_id) + ", " list_feature_id = aux[:-2] + "}" # Execute function function_name = "gw_fct_connect_to_network" sql = ("SELECT " + self.schema_name + "." + function_name + "" "('" + list_feature_id + "', '" + geom_type.upper() + "');") self.controller.execute_sql(sql, log_sql=True) layer.removeSelection() # Refresh map canvas self.rubber_band.reset() self.refresh_map_canvas() self.iface.actionPan().trigger() def set_rubber_band(self): # Coordinates transform transform = self.canvas.getCoordinateTransform() # Coordinates ll = transform.toMapCoordinates(self.select_rect.left(), self.select_rect.bottom()) lr = transform.toMapCoordinates(self.select_rect.right(), self.select_rect.bottom()) ul = transform.toMapCoordinates(self.select_rect.left(), self.select_rect.top()) ur = transform.toMapCoordinates(self.select_rect.right(), self.select_rect.top()) # Rubber band self.rubber_band.reset(QGis.Polygon) self.rubber_band.addPoint(ll, False) self.rubber_band.addPoint(lr, False) self.rubber_band.addPoint(ur, False) self.rubber_band.addPoint(ul, False) self.rubber_band.addPoint(ll, True) self.selected_rectangle = QgsRectangle(ll, ur) def select_multiple_features(self, selectGeometry): if self.layer_connec_man is None and self.layer_gully_man is None: return key = QApplication.keyboardModifiers() # If Ctrl+Shift clicked: remove features from selection if key == (Qt.ControlModifier | Qt.ShiftModifier): behaviour = QgsVectorLayer.RemoveFromSelection # If Ctrl clicked: add features to selection elif key == Qt.ControlModifier: behaviour = QgsVectorLayer.AddToSelection # If Ctrl not clicked: add features to selection else: behaviour = QgsVectorLayer.AddToSelection # Selection for all connec and gully layers for layer in self.layer_connec_man: layer.selectByRect(selectGeometry, behaviour) if self.layer_gully_man: for layer in self.layer_gully_man: layer.selectByRect(selectGeometry, behaviour)
class BrushingModel(QObject): brushSizeChanged = pyqtSignal(int) brushColorChanged = pyqtSignal(QColor) brushStrokeAvailable = pyqtSignal(QPointF, object) drawnNumberChanged = pyqtSignal(int) minBrushSize = 1 maxBrushSize = 61 defaultBrushSize = 3 defaultDrawnNumber = 1 defaultColor = Qt.white erasingColor = Qt.black erasingNumber = 100 def __init__(self, parent=None): QObject.__init__(self, parent=parent) self.sliceRect = None self.bb = QRect() #bounding box enclosing the drawing self.brushSize = self.defaultBrushSize self.drawColor = self.defaultColor self._temp_color = None self._temp_number = None self.drawnNumber = self.defaultDrawnNumber self.pos = None self.erasing = False self._hasMoved = False self.drawOnto = None #an empty scene, where we add all drawn line segments #a QGraphicsLineItem, and which we can use to then #render to an image self.scene = QGraphicsScene() def toggleErase(self): self.erasing = not(self.erasing) if self.erasing: self.setErasing() else: self.disableErasing() def setErasing(self): self.erasing = True self._temp_color = self.drawColor self._temp_number = self.drawnNumber self.setBrushColor(self.erasingColor) self.brushColorChanged.emit(self.erasingColor) self.setDrawnNumber(self.erasingNumber) def disableErasing(self): self.erasing = False self.setBrushColor(self._temp_color) self.brushColorChanged.emit(self.drawColor) self.setDrawnNumber(self._temp_number) def setBrushSize(self, size): self.brushSize = size self.brushSizeChanged.emit(self.brushSize) def setDrawnNumber(self, num): self.drawnNumber = num self.drawnNumberChanged.emit(num) def getBrushSize(self): return self.brushSize def brushSmaller(self): b = self.brushSize if b > self.minBrushSize: self.setBrushSize(b-1) def brushBigger(self): b = self.brushSize if self.brushSize < self.maxBrushSize: self.setBrushSize(b+1) def setBrushColor(self, color): self.drawColor = color self.brushColorChanged.emit(self.drawColor) def beginDrawing(self, pos, sliceRect): ''' pos -- QPointF-like ''' self.sliceRect = sliceRect self.scene.clear() self.bb = QRect() self.pos = QPointF(pos.x(), pos.y()) self._hasMoved = False def endDrawing(self, pos): has_moved = self._hasMoved # _hasMoved will change after calling moveTo if has_moved: self.moveTo(pos) else: assert(self.pos == pos) self.moveTo(QPointF(pos.x()+0.0001, pos.y()+0.0001)) # move a little # Qt seems to use strange rules for determining which pixels to set when rendering a brush stroke to a QImage. # We seem to get better results if we do the following: # 1) Slightly offset the source window because apparently there is a small shift in the data # 2) Render the scene to an image that is MUCH larger than the scene resolution (4x by 4x) # 3) Downsample each 4x4 patch from the large image back to a single pixel in the final image, # applying some threshold to determine if the final pixel is on or off. tempi = QImage(QSize(4*self.bb.width(), 4*self.bb.height()), QImage.Format_ARGB32_Premultiplied) #TODO: format tempi.fill(0) painter = QPainter(tempi) # Offset the source window. At first I thought the right offset was 0.5, because # that would seem to make sure points are rounded to pixel CENTERS, but # experimentation indicates that 0.25 is slightly better for some reason... source_rect = QRectF( QPointF(self.bb.x()+0.25, self.bb.y()+0.25), QSizeF(self.bb.width(), self.bb.height()) ) target_rect = QRectF( QPointF(0,0), QSizeF(4*self.bb.width(), 4*self.bb.height()) ) self.scene.render(painter, target=target_rect, source=source_rect) painter.end() # Now downsample: convert each 4x4 patch into a single pixel by summing and dividing ndarr = qimage2ndarray.rgb_view(tempi)[:,:,0].astype(int) ndarr = ndarr.reshape( (ndarr.shape[0],) + (ndarr.shape[1]//4,) + (4,) ) ndarr = ndarr.sum(axis=-1) ndarr = ndarr.transpose() ndarr = ndarr.reshape( (ndarr.shape[0],) + (ndarr.shape[1]//4,) + (4,) ) ndarr = ndarr.sum(axis=-1) ndarr = ndarr.transpose() ndarr //= 4*4 downsample_threshold = (7./16)*255 labels = numpy.where(ndarr>=downsample_threshold, numpy.uint8(self.drawnNumber), numpy.uint8(0)) labels = labels.swapaxes(0,1) assert labels.shape[0] == self.bb.width() assert labels.shape[1] == self.bb.height() ## ## ensure that at least one pixel is label when the brush size is 1 ## ## this happens when the user just clicked without moving ## in that case the lineitem will be so tiny, that it won't be rendered ## into a single pixel by the code above if not has_moved and self.brushSize <= 1 and numpy.count_nonzero(labels) == 0: labels[labels.shape[0]//2, labels.shape[1]//2] = self.drawnNumber self.brushStrokeAvailable.emit(QPointF(self.bb.x(), self.bb.y()), labels) def dumpDraw(self, pos): res = self.endDrawing(pos) self.beginDrawing(pos, self.sliceRect) return res def moveTo(self, pos): #data coordinates oldX, oldY = self.pos.x(), self.pos.y() x,y = pos.x(), pos.y() line = QGraphicsLineItem(oldX, oldY, x, y) line.setPen(QPen( QBrush(Qt.white), self.brushSize, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) self.scene.addItem(line) self._hasMoved = True #update bounding Box if not self.bb.isValid(): self.bb = QRect(QPoint(oldX,oldY), QSize(1,1)) #grow bounding box self.bb.setLeft( min(self.bb.left(), max(0, x-self.brushSize//2-1) ) ) self.bb.setRight( max(self.bb.right(), min(self.sliceRect[0]-1, x+self.brushSize//2+1) ) ) self.bb.setTop( min(self.bb.top(), max(0, y-self.brushSize//2-1) ) ) self.bb.setBottom(max(self.bb.bottom(), min(self.sliceRect[1]-1, y+self.brushSize//2+1) ) ) #update/move position self.pos = pos
class SelectByRect(QgsMapTool): def __init__(self, canvas): self.mCanvas = canvas QgsMapTool.__init__(self, canvas) self.mCursor = Qt.ArrowCursor self.mRubberBand = None self.mDragging = False self.mSelectRect = QRect() # QgsRubberBand* mRubberBand; # def reset(self): # self.startPoint = None # self.endPoint = None # self.isDrawing = False # SelectByRect.RubberRect.reset(QGis.Polygon) # self.layer = self.canvas.currentLayer() def canvasPressEvent(self, e): self.mSelectRect.setRect(0, 0, 0, 0) self.mRubberBand = QgsRubberBand(self.mCanvas, QGis.Polygon) # self.reset() # self.startPoint = self.toMapCoordinates(e.pos()) # self.isDrawing = True def canvasMoveEvent(self, e): if (e.buttons() != Qt.LeftButton): return if (not self.mDragging): self.mDragging = True self.mSelectRect.setTopLeft(e.pos()) self.mSelectRect.setBottomRight(e.pos()) QgsMapToolSelectUtils.setRubberBand(self.mCanvas, self.mSelectRect, self.mRubberBand) # if not self.isDrawing: # return # SelectByRect.RubberRect.reset(QGis.Polygon) # self.endPoint = self.toMapCoordinates(e.pos()) # self.rect = QgsRectangle(self.startPoint, self.endPoint) # SelectByRect.RubberRect.addGeometry(QgsGeometry.fromRect(self.rect), None) # SelectByRect.RubberRect.show() def canvasReleaseEvent(self, e): selectedFeatures = None vlayer = QgsMapToolSelectUtils.getCurrentVectorLayer(self.mCanvas) if (vlayer == None): if (self.mRubberBand != None): self.mRubberBand.reset(QGis.Polygon) del self.mRubberBand self.mRubberBand = None self.mDragging = False return if (not self.mDragging): QgsMapToolSelectUtils.expandSelectRectangle( self.mSelectRect, vlayer, e.pos()) else: if (self.mSelectRect.width() == 1): self.mSelectRect.setLeft(self.mSelectRect.left() + 1) if (self.mSelectRect.height() == 1): self.mSelectRect.setBottom(self.mSelectRect.bottom() + 1) if (self.mRubberBand != None): QgsMapToolSelectUtils.setRubberBand(self.mCanvas, self.mSelectRect, self.mRubberBand) selectGeom = self.mRubberBand.asGeometry() # QgsMapToolSelectUtils.setSelectFeatures( self.mCanvas, selectGeom, e ) selectedFeatures = QgsMapToolSelectUtils.setSelectFeatures1( self.mCanvas, selectGeom, e) del selectGeom self.mRubberBand.reset(QGis.Polygon) del self.mRubberBand self.mRubberBand = None self.mDragging = False self.emit(SIGNAL("getSelectedFeatures"), selectedFeatures)
class SelectedFeatureByRectTasDraw(QgsMapTool): def __init__(self, canvas, distance): self.mCanvas = canvas QgsMapTool.__init__(self, canvas) self.mCursor = Qt.ArrowCursor self.mRubberBand = None self.mDragging = False self.mSelectRect = QRect() self.rubberBandLine = None self.distance = distance self.mSnapper = QgsMapCanvasSnapper(canvas) # QgsRubberBand* mRubberBand; # def reset(self): # self.startPoint = None # self.endPoint = None # self.isDrawing = False # SelectByRect.RubberRect.reset(QGis.Polygon) # self.layer = self.canvas.currentLayer() def canvasPressEvent(self, e): self.mSelectRect.setRect(0, 0, 0, 0) self.mRubberBand = QgsRubberBand(self.mCanvas, QGis.Polygon) self.startPoint, self.pointID, self.layer = self.snapPoint(e.pos()) # self.reset() # self.startPoint = self.toMapCoordinates(e.pos()) # self.isDrawing = True def canvasMoveEvent(self, e): if (e.buttons() != Qt.LeftButton): return if (not self.mDragging): self.mDragging = True self.mSelectRect.setTopLeft(e.pos()) self.mSelectRect.setBottomRight(e.pos()) QgsMapToolSelectUtils.setRubberBand(self.mCanvas, self.mSelectRect, self.mRubberBand) # if not self.isDrawing: # return # SelectByRect.RubberRect.reset(QGis.Polygon) # self.endPoint = self.toMapCoordinates(e.pos()) # self.rect = QgsRectangle(self.startPoint, self.endPoint) # SelectByRect.RubberRect.addGeometry(QgsGeometry.fromRect(self.rect), None) # SelectByRect.RubberRect.show() def canvasReleaseEvent(self, e): self.endPoint, self.pointID, self.layer = self.snapPoint(e.pos()) if len(define._newGeometryList) > 0: geom = define._newGeometryList[0] if geom.intersects(self.mRubberBand.asGeometry()): pointArray = geom.asPolyline() # pointArray1 = QgisHelper.offsetCurve(pointArray, 1200) if self.rubberBandLine != None: self.rubberBandLine.reset(QGis.Line) del self.rubberBandLine self.rubberBandLine = None self.rubberBandLine = QgsRubberBand(self.mCanvas, QGis.Line) self.rubberBandLine.setColor(Qt.blue) bearing = 0.0 if self.startPoint.y() >= self.endPoint.y() and ( math.fabs(self.startPoint.x() - self.endPoint.x()) < math.fabs(self.startPoint.y() - self.endPoint.y())): bearing = Unit.ConvertDegToRad(180) elif self.startPoint.x() >= self.endPoint.x() and ( math.fabs(self.startPoint.x() - self.endPoint.x()) > math.fabs(self.startPoint.y() - self.endPoint.y())): bearing = Unit.ConvertDegToRad(270) elif self.startPoint.x() < self.endPoint.x() and ( math.fabs(self.startPoint.x() - self.endPoint.x()) > math.fabs(self.startPoint.y() - self.endPoint.y())): bearing = Unit.ConvertDegToRad(90) else: bearing = 0.0 for point in pointArray: pt = MathHelper.distanceBearingPoint( Point3D(point.x(), point.y()), bearing, self.distance ) # MathHelper.getBearing(self.startPoint, self.endPoint), self.distance) self.rubberBandLine.addPoint(pt) gg = self.rubberBandLine.asGeometry() g = gg.asPolyline() # self.rubberBandLine.show() if (self.mRubberBand != None): self.mRubberBand.reset(QGis.Polygon) del self.mRubberBand self.mRubberBand = None self.mDragging = False self.emit( SIGNAL("resultSelectedFeatureByRectTasDraw"), gg, self.distance, bearing ) # MathHelper.getBearing(self.startPoint, self.endPoint)) return vlayer = QgsMapToolSelectUtils.getCurrentVectorLayer(self.mCanvas) if (vlayer == None): if (self.mRubberBand != None): self.mRubberBand.reset(QGis.Polygon) del self.mRubberBand self.mRubberBand = None self.mDragging = False return if (not self.mDragging): QgsMapToolSelectUtils.expandSelectRectangle( self.mSelectRect, vlayer, e.pos()) else: if (self.mSelectRect.width() == 1): self.mSelectRect.setLeft(self.mSelectRect.left() + 1) if (self.mSelectRect.height() == 1): self.mSelectRect.setBottom(self.mSelectRect.bottom() + 1) if (self.mRubberBand != None): QgsMapToolSelectUtils.setRubberBand(self.mCanvas, self.mSelectRect, self.mRubberBand) selectGeom = self.mRubberBand.asGeometry() # QgsMapToolSelectUtils.setSelectFeatures( self.mCanvas, selectGeom, e ) selectedFeatures = QgsMapToolSelectUtils.setSelectFeaturesOrRubberband_Tas_1( self.mCanvas, selectGeom, e) if len(selectedFeatures) > 0: geom = selectedFeatures[0].geometry() if geom.intersects(self.mRubberBand.asGeometry()): pointArray = geom.asPolyline() # pointArray1 = QgisHelper.offsetCurve(pointArray, 1200) if self.rubberBandLine != None: self.rubberBandLine.reset(QGis.Line) del self.rubberBandLine self.rubberBandLine = None self.rubberBandLine = QgsRubberBand( self.mCanvas, QGis.Line) self.rubberBandLine.setColor(Qt.blue) bearing = 0.0 gg = None if self.startPoint.y() >= self.endPoint.y() and ( math.fabs(self.startPoint.x() - self.endPoint.x()) < math.fabs(self.startPoint.y() - self.endPoint.y())): bearing = Unit.ConvertDegToRad(180) gg = self.newCreateLine(geom, self.distance, 180) elif self.startPoint.x() >= self.endPoint.x() and ( math.fabs(self.startPoint.x() - self.endPoint.x()) > math.fabs(self.startPoint.y() - self.endPoint.y())): bearing = Unit.ConvertDegToRad(270) gg = self.newCreateLine(geom, self.distance, 270) elif self.startPoint.x() < self.endPoint.x() and ( math.fabs(self.startPoint.x() - self.endPoint.x()) > math.fabs(self.startPoint.y() - self.endPoint.y())): bearing = Unit.ConvertDegToRad(90) gg = self.newCreateLine(geom, self.distance, 90) else: bearing = 0.0 gg = self.newCreateLine(geom, self.distance, 0) for point in pointArray: pt = MathHelper.distanceBearingPoint( Point3D(point.x(), point.y()), bearing, self.distance ) #MathHelper.getBearing(self.startPoint, self.endPoint), self.distance) self.rubberBandLine.addPoint(pt) # gg= self.newCreateLine(geom, -self.distance, 0) self.emit( SIGNAL("resultSelectedFeatureByRectTasDraw"), gg, self.distance, bearing ) #MathHelper.getBearing(self.startPoint, self.endPoint)) self.rubberBandLine.reset(QGis.Line) del selectGeom self.mRubberBand.reset(QGis.Polygon) del self.mRubberBand self.mRubberBand = None self.mDragging = False # self.canvasMoveEvent(e) # if self.layer != None: # self.layer.removeSelection() # if self.layer.crs().mapUnits() != self.canvas.mapUnits(): # if self.layer.crs().mapUnits == QGis.Meters: # lstPoint = QgisHelper.Degree2MeterList([self.startPoint, self.endPoint]) # else: # lstPoint = QgisHelper.Meter2DegreeList([self.startPoint, self.endPoint]) # rect = QgsRectangle(lstPoint[0], lstPoint[1]) # self.layer.select(rect, True) # else: # self.layer.select(self.rect, False) # else: # QMessageBox.warning(None, "Information", "Please select layer!") # self.reset() def snapPoint(self, p, bNone=False): if define._snapping == False: return ( define._canvas.getCoordinateTransform().toMapCoordinates(p), None, None) snappingResults = self.mSnapper.snapToBackgroundLayers(p) if (snappingResults[0] != 0 or len(snappingResults[1]) < 1): if bNone: return (None, None, None) else: return (define._canvas.getCoordinateTransform(). toMapCoordinates(p), None, None) else: return (snappingResults[1][0].snappedVertex, snappingResults[1][0].snappedAtGeometry, snappingResults[1][0].layer) def newCreateLine(self, geom, dist, angle): if define._units != QGis.Meters: dist = define._qgsDistanceArea.convertMeasurement( dist, QGis.Meters, QGis.Degrees, False)[0] g = geom.offsetCurve(dist, 0, 2, 2) pointArrayOld = geom.asPolyline() pointArrayNew = g.asPolyline() if MathHelper.calcDistance( pointArrayNew[0], pointArrayOld[0]) > MathHelper.calcDistance( pointArrayNew[0], pointArrayOld[len(pointArrayOld) - 1]): array = [] i = len(pointArrayNew) - 1 while i >= 0: array.append(pointArrayNew[i]) i -= 1 pointArrayNew = array if angle == 0: if pointArrayNew[0].y() < pointArrayOld[0].y(): g = geom.offsetCurve(-dist, 0, 2, 2) pointArrayNew = g.asPolyline() elif angle == 90: if pointArrayNew[0].x() < pointArrayOld[0].x(): g = geom.offsetCurve(-dist, 0, 2, 2) pointArrayNew = g.asPolyline() elif angle == 180: if pointArrayNew[0].y() > pointArrayOld[0].y(): g = geom.offsetCurve(-dist, 0, 2, 2) pointArrayNew = g.asPolyline() elif angle == 270: if pointArrayNew[0].x() > pointArrayOld[0].x(): g = geom.offsetCurve(-dist, 0, 2, 2) pointArrayNew = g.asPolyline() if MathHelper.calcDistance( pointArrayNew[0], pointArrayOld[0]) > MathHelper.calcDistance( pointArrayNew[0], pointArrayOld[len(pointArrayOld) - 1]): array = [] i = len(pointArrayNew) - 1 while i >= 0: array.append(pointArrayNew[i]) i -= 1 pointArrayNew = array i = 0 while i < len(pointArrayNew) - 1: if i == 0: i += 1 continue line = None if define._units == QGis.Meters: if angle == 0: line = QgsGeometry.fromPolyline([ pointArrayOld[0], QgsPoint(pointArrayOld[0].x(), 100000000) ]) elif angle == 90: line = QgsGeometry.fromPolyline([ pointArrayOld[0], QgsPoint(100000000, pointArrayOld[0].y()) ]) elif angle == 180: line = QgsGeometry.fromPolyline( [pointArrayOld[0], QgsPoint(pointArrayOld[0].x(), 0)]) elif angle == 270: line = QgsGeometry.fromPolyline( [pointArrayOld[0], QgsPoint(0, pointArrayOld[0].y())]) else: if angle == 0: line = QgsGeometry.fromPolyline([ pointArrayOld[0], QgsPoint(pointArrayOld[0].x(), pointArrayOld[0].y() + 0.1) ]) elif angle == 90: line = QgsGeometry.fromPolyline([ pointArrayOld[0], QgsPoint(pointArrayOld[0].x() + 0.1, pointArrayOld[0].y()) ]) elif angle == 180: line = QgsGeometry.fromPolyline([ pointArrayOld[0], QgsPoint(pointArrayOld[0].x(), pointArrayOld[0].y() - 0.1) ]) elif angle == 270: line = QgsGeometry.fromPolyline([ pointArrayOld[0], QgsPoint(pointArrayOld[0].x() - 0.1, pointArrayOld[0].y()) ]) lineNew = QgsGeometry.fromPolyline([ MathHelper.distanceBearingPoint( Point3D(pointArrayNew[i].x(), pointArrayNew[i].y()), MathHelper.getBearing(pointArrayNew[i], pointArrayNew[i - 1]), 100000), pointArrayNew[i] ]) if line.intersects(lineNew): pointGeom = line.intersection(lineNew) intersectPoint = pointGeom.asPoint() pointArrayNew.pop(i - 1) pointArrayNew.insert(i - 1, intersectPoint) break else: pointArrayNew.pop(i - 1) continue i += 1 i = len(pointArrayNew) - 1 while i > 1: line = None if define._units == QGis.Meters: if angle == 0: line = QgsGeometry.fromPolyline([ pointArrayOld[len(pointArrayOld) - 1], QgsPoint(pointArrayOld[len(pointArrayOld) - 1].x(), 100000000) ]) elif angle == 90: line = QgsGeometry.fromPolyline([ pointArrayOld[len(pointArrayOld) - 1], QgsPoint(100000000, pointArrayOld[len(pointArrayOld) - 1].y()) ]) elif angle == 180: line = QgsGeometry.fromPolyline([ pointArrayOld[len(pointArrayOld) - 1], QgsPoint(pointArrayOld[len(pointArrayOld) - 1].x(), 0) ]) elif angle == 270: line = QgsGeometry.fromPolyline([ pointArrayOld[len(pointArrayOld) - 1], QgsPoint(0, pointArrayOld[len(pointArrayOld) - 1].y()) ]) else: if angle == 0: line = QgsGeometry.fromPolyline([ pointArrayOld[len(pointArrayOld) - 1], QgsPoint( pointArrayOld[len(pointArrayOld) - 1].x(), pointArrayOld[len(pointArrayOld) - 1].y() + 0.1) ]) elif angle == 90: line = QgsGeometry.fromPolyline([ pointArrayOld[len(pointArrayOld) - 1], QgsPoint( pointArrayOld[len(pointArrayOld) - 1].x() + 0.1, pointArrayOld[len(pointArrayOld) - 1].y()) ]) elif angle == 180: line = QgsGeometry.fromPolyline([ pointArrayOld[len(pointArrayOld) - 1], QgsPoint( pointArrayOld[len(pointArrayOld) - 1].x(), pointArrayOld[len(pointArrayOld) - 1].y() - 0.1) ]) elif angle == 270: line = QgsGeometry.fromPolyline([ pointArrayOld[len(pointArrayOld) - 1], QgsPoint( pointArrayOld[len(pointArrayOld) - 1].x() - 0.1, pointArrayOld[len(pointArrayOld) - 1].y()) ]) # line = QgsGeometry.fromPolyline([pointArrayOld[len(pointArrayOld) - 1], QgsPoint(pointArrayOld[len(pointArrayOld) - 1].x(), 100000000)]) lineNew = QgsGeometry.fromPolyline([ MathHelper.distanceBearingPoint( Point3D(pointArrayNew[i].x(), pointArrayNew[i].y()), MathHelper.getBearing(pointArrayNew[i - 1], pointArrayNew[i]), 100000), pointArrayNew[i - 1] ]) if line.intersects(lineNew): pointGeom = line.intersection(lineNew) intersectPoint = pointGeom.asPoint() pointArrayNew.pop(i) pointArrayNew.insert(i, intersectPoint) break else: pointArrayNew.pop(i) i -= 1 continue i -= 1 return QgsGeometry.fromPolyline(pointArrayNew)
class BrushingModel(QObject): brushSizeChanged = pyqtSignal(int) brushColorChanged = pyqtSignal(QColor) brushStrokeAvailable = pyqtSignal(QPointF, object) drawnNumberChanged = pyqtSignal(int) minBrushSize = 1 maxBrushSize = 61 defaultBrushSize = 3 defaultDrawnNumber = 1 defaultColor = Qt.white erasingColor = Qt.black erasingNumber = 100 def __init__(self, parent=None): QObject.__init__(self, parent=parent) self.sliceRect = None self.bb = QRect() #bounding box enclosing the drawing self.brushSize = self.defaultBrushSize self.drawColor = self.defaultColor self._temp_color = None self._temp_number = None self.drawnNumber = self.defaultDrawnNumber self.pos = None self.erasing = False self._hasMoved = False self.drawOnto = None #an empty scene, where we add all drawn line segments #a QGraphicsLineItem, and which we can use to then #render to an image self.scene = QGraphicsScene() def toggleErase(self): self.erasing = not (self.erasing) if self.erasing: self.setErasing() else: self.disableErasing() def setErasing(self): self.erasing = True self._temp_color = self.drawColor self._temp_number = self.drawnNumber self.setBrushColor(self.erasingColor) self.brushColorChanged.emit(self.erasingColor) self.setDrawnNumber(self.erasingNumber) def disableErasing(self): self.erasing = False self.setBrushColor(self._temp_color) self.brushColorChanged.emit(self.drawColor) self.setDrawnNumber(self._temp_number) def setBrushSize(self, size): self.brushSize = size self.brushSizeChanged.emit(self.brushSize) def setDrawnNumber(self, num): self.drawnNumber = num self.drawnNumberChanged.emit(num) def getBrushSize(self): return self.brushSize def brushSmaller(self): b = self.brushSize if b > self.minBrushSize: self.setBrushSize(b - 1) def brushBigger(self): b = self.brushSize if self.brushSize < self.maxBrushSize: self.setBrushSize(b + 1) def setBrushColor(self, color): self.drawColor = color self.brushColorChanged.emit(self.drawColor) def beginDrawing(self, pos, sliceRect): ''' pos -- QPointF-like ''' self.sliceRect = sliceRect self.scene.clear() self.bb = QRect() self.pos = QPointF(pos.x(), pos.y()) self._hasMoved = False def endDrawing(self, pos): has_moved = self._hasMoved # _hasMoved will change after calling moveTo if has_moved: self.moveTo(pos) else: assert (self.pos == pos) self.moveTo(QPointF(pos.x() + 0.0001, pos.y() + 0.0001)) # move a little tempi = QImage(QSize(self.bb.width(), self.bb.height()), QImage.Format_ARGB32_Premultiplied) #TODO: format tempi.fill(0) painter = QPainter(tempi) self.scene.render(painter, target=QRectF(), source=QRectF( QPointF(self.bb.x(), self.bb.y()), QSizeF(self.bb.width(), self.bb.height()))) painter.end() ndarr = qimage2ndarray.rgb_view(tempi)[:, :, 0] labels = numpy.where(ndarr > 0, numpy.uint8(self.drawnNumber), numpy.uint8(0)) labels = labels.swapaxes(0, 1) assert labels.shape[0] == self.bb.width() assert labels.shape[1] == self.bb.height() ## ## ensure that at least one pixel is label when the brush size is 1 ## ## this happens when the user just clicked without moving ## in that case the lineitem will be so tiny, that it won't be rendered ## into a single pixel by the code above if not has_moved and self.brushSize <= 1 and numpy.count_nonzero( labels) == 0: labels[labels.shape[0] // 2, labels.shape[1] // 2] = self.drawnNumber self.brushStrokeAvailable.emit(QPointF(self.bb.x(), self.bb.y()), labels) def dumpDraw(self, pos): res = self.endDrawing(pos) self.beginDrawing(pos, self.sliceRect) return res def moveTo(self, pos): #data coordinates oldX, oldY = self.pos.x(), self.pos.y() x, y = pos.x(), pos.y() line = QGraphicsLineItem(oldX, oldY, x, y) line.setPen( QPen(QBrush(Qt.white), self.brushSize, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) self.scene.addItem(line) self._hasMoved = True #update bounding Box if not self.bb.isValid(): self.bb = QRect(QPoint(oldX, oldY), QSize(1, 1)) #grow bounding box self.bb.setLeft(min(self.bb.left(), max(0, x - self.brushSize / 2 - 1))) self.bb.setRight( max(self.bb.right(), min(self.sliceRect[0] - 1, x + self.brushSize / 2 + 1))) self.bb.setTop(min(self.bb.top(), max(0, y - self.brushSize / 2 - 1))) self.bb.setBottom( max(self.bb.bottom(), min(self.sliceRect[1] - 1, y + self.brushSize / 2 + 1))) #update/move position self.pos = pos
class ObstacleAreaJigSelectArea(QgsMapTool): def __init__(self, canvas, areaType): self.mCanvas = canvas self.areaType = areaType QgsMapTool.__init__(self, canvas) self.mCursor = Qt.ArrowCursor self.mRubberBand = None self.mDragging = False self.mSelectRect = QRect() self.mRubberBandResult = None self.mSnapper = QgsMapCanvasSnapper(canvas) self.lineCount = 0 self.resultGeomList = [] self.geomList = [] self.area = None self.isFinished = False # QgsRubberBand* mRubberBand; # def reset(self): # self.startPoint = None # self.endPoint = None # self.isDrawing = False # SelectByRect.RubberRect.reset(QGis.Polygon) # self.layer = self.canvas.currentLayer() def canvasPressEvent(self, e): QgisHelper.ClearRubberBandInCanvas(define._canvas) self.mSelectRect.setRect( 0, 0, 0, 0 ) self.mRubberBand = QgsRubberBand( self.mCanvas, QGis.Polygon ) self.startPoint, self.pointID, self.layer= self.snapPoint(e.pos()) def canvasMoveEvent(self, e): if self.areaType == ProtectionAreaType.Secondary: if self.lineCount == 0: define._messageLabel.setText("Select a line or arc representing the INNER edge of the secondary area.") elif self.lineCount == 1: define._messageLabel.setText("Select a line representing the OUTER edge of the secondary area.") elif self.areaType == ProtectionAreaType.Primary: define._messageLabel.setText("") elif self.areaType == ProtectionAreaType.PrimaryAndSecondary: if self.lineCount == 0: define._messageLabel.setText("Select a line or arc representing the INNER edge of the FIRST secondary area.") elif self.lineCount == 1: define._messageLabel.setText("Select a line representing the OUTER edge of the FIRST secondary area.") elif self.lineCount == 2: define._messageLabel.setText("Select a line or arc representing the INNER edge of the SECOND secondary area.") elif self.lineCount == 3: define._messageLabel.setText("Select a line representing the OUTER edge of the SECOND secondary area.") else: define._messageLabel.setText("") if ( e.buttons() != Qt.LeftButton ): return if ( not self.mDragging ): self.mDragging = True self.mSelectRect.setTopLeft( e.pos() ) self.mSelectRect.setBottomRight( e.pos() ) QgsMapToolSelectUtils.setRubberBand( self.mCanvas, self.mSelectRect,self.mRubberBand ) def canvasReleaseEvent(self, e): self.endPoint, self.pointID, self.layer= self.snapPoint(e.pos()) vlayer = QgsMapToolSelectUtils.getCurrentVectorLayer( self.mCanvas ) if ( vlayer == None ): if ( self.mRubberBand != None): self.mRubberBand.reset( QGis.Polygon ) del self.mRubberBand self.mRubberBand = None self.mDragging = False return if (not self.mDragging ): QgsMapToolSelectUtils.expandSelectRectangle(self. mSelectRect, vlayer, e.pos() ) else: if ( self.mSelectRect.width() == 1 ): self.mSelectRect.setLeft( self.mSelectRect.left() + 1 ) if ( self.mSelectRect.height() == 1 ): self.mSelectRect.setBottom( self.mSelectRect.bottom() + 1 ) if ( self.mRubberBand != None ): QgsMapToolSelectUtils.setRubberBand( self.mCanvas, self.mSelectRect, self.mRubberBand ) selectGeom = self.mRubberBand.asGeometry() selectedFeatures = QgsMapToolSelectUtils.setSelectFeaturesOrRubberband_Tas_1( self.mCanvas, selectGeom, e ) if len(selectedFeatures) > 0: self.lineCount += 1 geom = selectedFeatures[0].geometry() resultArray = QgisHelper.findArcOrLineInLineGeometry(geom, selectGeom) # if resultArray != None: # bulge = MathHelper.smethod_60(resultArray[0], resultArray[int(len(resultArray)/2)], resultArray[len(resultArray)-1]) # bulge1 = MathHelper.smethod_60(resultArray[len(resultArray)-1], resultArray[int(len(resultArray)/2)], resultArray[0]) # n = 0 pointArray0 = geom.asPolyline() self.resultGeomList.append(resultArray) self.geomList.append(pointArray0) if self.lineCount == 2 and self.areaType != ProtectionAreaType.PrimaryAndSecondary and self.areaType != ProtectionAreaType.Complex: self.area = self.makeArea(self.resultGeomList, self.areaType) pointArray = self.getPointArray(self.resultGeomList).method_14_closed() self.mRubberBandResult = None self.mRubberBandResult = QgsRubberBand( self.mCanvas, QGis.Polygon ) self.mRubberBandResult.setFillColor(QColor(255, 255, 255, 100)) self.mRubberBandResult.setBorderColor(QColor(0, 0, 0)) for point in pointArray: self.mRubberBandResult.addPoint(point) self.mRubberBandResult.show() self.emit(SIGNAL("outputResult"), self.area, self.mRubberBandResult) self.lineCount = 0 self.resultGeomList = [] self.isFinished = True # self.rubberBandLine.reset(QGis.Line) elif self.lineCount == 4 and self.areaType == ProtectionAreaType.PrimaryAndSecondary: self.area = self.makeArea(self.resultGeomList, self.areaType) pointArray = self.getPointArray([self.resultGeomList[1], self.resultGeomList[3]]).method_14_closed() self.mRubberBandResult = None self.mRubberBandResult = QgsRubberBand( self.mCanvas, QGis.Polygon ) self.mRubberBandResult.setFillColor(QColor(255, 255, 255, 100)) self.mRubberBandResult.setBorderColor(QColor(0, 0, 0)) for point in pointArray: self.mRubberBandResult.addPoint(point) self.mRubberBandResult.show() self.emit(SIGNAL("outputResult"), self.area, self.mRubberBandResult) self.lineCount = 0 self.resultGeomList = [] # else: # return del selectGeom self.mRubberBand.reset( QGis.Polygon ) del self.mRubberBand self.mRubberBand = None self.mDragging = False def getPointArray(self, geomList): pointArrayInner = geomList[0] pointArray1Outer = geomList[1] innerStartPoint = pointArrayInner[0] innerEndPoint = pointArrayInner[1] innerBulge = pointArrayInner[2] outerStartPoint = pointArray1Outer[0] outerEndPoint = pointArray1Outer[1] outerBulge = pointArray1Outer[2] line0 = QgsGeometry.fromPolyline([innerStartPoint, outerStartPoint]) line1 = QgsGeometry.fromPolyline([innerEndPoint, outerEndPoint]) # for i in range(1, len(pointArray0)): if line0.intersects(line1): tempPoint = outerStartPoint outerStartPoint = outerEndPoint outerEndPoint = tempPoint outerBulge = -outerBulge polylineArea = PolylineArea() polylineArea.Add(PolylineAreaPoint(innerStartPoint, innerBulge)) polylineArea.Add(PolylineAreaPoint(innerEndPoint)) polylineArea.Add(PolylineAreaPoint(outerEndPoint, -outerBulge)) polylineArea.Add(PolylineAreaPoint(outerStartPoint)) return polylineArea def makeArea(self, geomList, areaType): if areaType == ProtectionAreaType.Primary or areaType == ProtectionAreaType.Secondary: return self.makePrimaryAreaOrSecondaryArea(geomList, areaType) elif areaType == ProtectionAreaType.PrimaryAndSecondary: pointArray0 = geomList[0] pointArray1 = geomList[1] pointArray2 = geomList[2] pointArray3 = geomList[3] primaryArea = self.makePrimaryAreaOrSecondaryArea([pointArray0, pointArray2], ProtectionAreaType.Primary) secondaryArea1 = self.makePrimaryAreaOrSecondaryArea([pointArray0, pointArray1], ProtectionAreaType.Secondary) secondaryArea2 = self.makePrimaryAreaOrSecondaryArea([pointArray2, pointArray3], ProtectionAreaType.Secondary) return PrimarySecondaryObstacleArea(primaryArea, secondaryArea1, secondaryArea2) # if len(geomList[0]) == 2 and len(geomList[1]) == 2 and len(geomList[2]) == 2 and len(geomList[3]) == 2: # for i in range(1, len(geomList)): # pointArray0 = geomList[0] # pointArray1 = geomList[i] # line0 = QgsGeometry.fromPolyline([pointArray0[0], pointArray1[0]]) # line1 = QgsGeometry.fromPolyline([pointArray0[len(pointArray0) - 1], pointArray1[len(pointArray1) - 1]]) # if line0.intersects(line1): # pointArray1.reverse() # pointArray0 = geomList[0] # pointArray1 = geomList[1] # pointArray2 = geomList[2] # pointArray3 = geomList[3] # area = PrimarySecondaryObstacleArea() # area.set_areas(pointArray0, pointArray1, pointArray2, pointArray3) # return area # return None return None def makePrimaryAreaOrSecondaryArea(self, geomList, areaType): pointArrayInner = geomList[0] pointArray1Outer = geomList[1] innerStartPoint = pointArrayInner[0] innerEndPoint = pointArrayInner[1] innerBulge = pointArrayInner[2] outerStartPoint = pointArray1Outer[0] outerEndPoint = pointArray1Outer[1] outerBulge = pointArray1Outer[2] line0 = QgsGeometry.fromPolyline([innerStartPoint, outerStartPoint]) line1 = QgsGeometry.fromPolyline([innerEndPoint, outerEndPoint]) # for i in range(1, len(pointArray0)): if line0.intersects(line1): tempPoint = Point3D(outerStartPoint.get_X(), outerStartPoint.get_Y()) outerStartPoint = Point3D(outerEndPoint.get_X(), outerEndPoint.get_Y()) outerEndPoint = Point3D(tempPoint.get_X(), tempPoint.get_Y()) outerBulge = -outerBulge if areaType == ProtectionAreaType.Primary: polylineArea = PolylineArea() polylineArea.Add(PolylineAreaPoint(innerStartPoint, innerBulge)) polylineArea.Add(PolylineAreaPoint(innerEndPoint)) polylineArea.Add(PolylineAreaPoint(outerEndPoint, -outerBulge)) polylineArea.Add(PolylineAreaPoint(outerStartPoint)) return PrimaryObstacleArea(polylineArea) elif areaType == ProtectionAreaType.Secondary: if innerBulge == 0 and outerBulge == 0: return SecondaryObstacleArea(innerStartPoint, innerEndPoint, outerStartPoint, outerEndPoint, MathHelper.getBearing(innerStartPoint, innerEndPoint)) elif innerBulge != 0 and outerBulge != 0: if round(innerBulge, 1) != round(outerBulge, 1): return None innerCenterPoint = MathHelper.smethod_71(innerStartPoint, innerEndPoint, innerBulge) outerCenterPoint = MathHelper.smethod_71(outerStartPoint, outerEndPoint, outerBulge) innerRadius = MathHelper.calcDistance(innerCenterPoint, innerStartPoint); outerRadius = MathHelper.calcDistance(outerCenterPoint, outerStartPoint); bearing = (MathHelper.getBearing(innerCenterPoint, innerStartPoint) + MathHelper.getBearing(innerCenterPoint, innerEndPoint)) / 2 innerMiddlePoint = MathHelper.distanceBearingPoint(innerCenterPoint, bearing, innerRadius) if round(MathHelper.smethod_60(innerStartPoint, innerMiddlePoint, innerEndPoint), 4) != round(outerBulge, 4): bearing += 3.14159265358979 innerMiddlePoint = MathHelper.distanceBearingPoint(innerCenterPoint, bearing, innerRadius) bearing = (MathHelper.getBearing(outerCenterPoint, outerStartPoint) + MathHelper.getBearing(outerCenterPoint, outerEndPoint)) / 2 outerMiddlePoint = MathHelper.distanceBearingPoint(outerCenterPoint, bearing, outerRadius) if round(MathHelper.smethod_60(outerStartPoint, outerMiddlePoint, outerEndPoint), 4) != round(outerBulge, 4): bearing += 3.14159265358979 outerMiddlePoint = MathHelper.distanceBearingPoint(outerCenterPoint, bearing, outerRadius) return SecondaryObstacleArea(innerStartPoint, innerMiddlePoint, innerEndPoint, outerStartPoint, None, outerMiddlePoint, outerEndPoint, innerBulge, innerBulge) return None def snapPoint(self, p, bNone = False): if define._snapping == False: return (define._canvas.getCoordinateTransform().toMapCoordinates( p ), None, None) snappingResults = self.mSnapper.snapToBackgroundLayers( p ) if ( snappingResults[0] != 0 or len(snappingResults[1]) < 1 ): if bNone: return (None, None, None) else: return (define._canvas.getCoordinateTransform().toMapCoordinates( p ), None, None) else: return (snappingResults[1][0].snappedVertex, snappingResults[1][0].snappedAtGeometry, snappingResults[1][0].layer)
class BrushingModel(QObject): brushSizeChanged = pyqtSignal(int) brushColorChanged = pyqtSignal(QColor) brushStrokeAvailable = pyqtSignal(QPointF, object) drawnNumberChanged = pyqtSignal(int) minBrushSize = 1 maxBrushSize = 61 defaultBrushSize = 3 defaultDrawnNumber = 1 defaultColor = Qt.white erasingColor = Qt.black erasingNumber = 100 def __init__(self, parent=None): QObject.__init__(self, parent=parent) self.sliceRect = None self.bb = QRect() #bounding box enclosing the drawing self.brushSize = self.defaultBrushSize self.drawColor = self.defaultColor self._temp_color = None self._temp_number = None self.drawnNumber = self.defaultDrawnNumber self.pos = None self.erasing = False self._hasMoved = False self.drawOnto = None #an empty scene, where we add all drawn line segments #a QGraphicsLineItem, and which we can use to then #render to an image self.scene = QGraphicsScene() def toggleErase(self): self.erasing = not(self.erasing) if self.erasing: self.setErasing() else: self.disableErasing() def setErasing(self): self.erasing = True self._temp_color = self.drawColor self._temp_number = self.drawnNumber self.setBrushColor(self.erasingColor) self.brushColorChanged.emit(self.erasingColor) self.setDrawnNumber(self.erasingNumber) def disableErasing(self): self.erasing = False self.setBrushColor(self._temp_color) self.brushColorChanged.emit(self.drawColor) self.setDrawnNumber(self._temp_number) def setBrushSize(self, size): self.brushSize = size self.brushSizeChanged.emit(self.brushSize) def setDrawnNumber(self, num): self.drawnNumber = num self.drawnNumberChanged.emit(num) def getBrushSize(self): return self.brushSize def brushSmaller(self): b = self.brushSize if b > self.minBrushSize: self.setBrushSize(b-1) def brushBigger(self): b = self.brushSize if self.brushSize < self.maxBrushSize: self.setBrushSize(b+1) def setBrushColor(self, color): self.drawColor = color self.brushColorChanged.emit(self.drawColor) def beginDrawing(self, pos, sliceRect): ''' pos -- QPointF-like ''' self.sliceRect = sliceRect self.scene.clear() self.bb = QRect() self.pos = QPointF(pos.x(), pos.y()) self._hasMoved = False def endDrawing(self, pos): has_moved = self._hasMoved # _hasMoved will change after calling moveTo if has_moved: self.moveTo(pos) else: assert(self.pos == pos) self.moveTo(QPointF(pos.x()+0.0001, pos.y()+0.0001)) # move a little tempi = QImage(QSize(self.bb.width(), self.bb.height()), QImage.Format_ARGB32_Premultiplied) #TODO: format tempi.fill(0) painter = QPainter(tempi) self.scene.render(painter, target=QRectF(), source=QRectF(QPointF(self.bb.x(), self.bb.y()), QSizeF(self.bb.width(), self.bb.height()))) painter.end() ndarr = qimage2ndarray.rgb_view(tempi)[:,:,0] labels = numpy.where(ndarr>0,numpy.uint8(self.drawnNumber),numpy.uint8(0)) labels = labels.swapaxes(0,1) assert labels.shape[0] == self.bb.width() assert labels.shape[1] == self.bb.height() ## ## ensure that at least one pixel is label when the brush size is 1 ## ## this happens when the user just clicked without moving ## in that case the lineitem will be so tiny, that it won't be rendered ## into a single pixel by the code above if not has_moved and self.brushSize <= 1 and numpy.count_nonzero(labels) == 0: labels[labels.shape[0]//2, labels.shape[1]//2] = self.drawnNumber self.brushStrokeAvailable.emit(QPointF(self.bb.x(), self.bb.y()), labels) def dumpDraw(self, pos): res = self.endDrawing(pos) self.beginDrawing(pos, self.sliceRect) return res def moveTo(self, pos): #data coordinates oldX, oldY = self.pos.x(), self.pos.y() x,y = pos.x(), pos.y() line = QGraphicsLineItem(oldX, oldY, x, y) line.setPen(QPen( QBrush(Qt.white), self.brushSize, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) self.scene.addItem(line) self._hasMoved = True #update bounding Box if not self.bb.isValid(): self.bb = QRect(QPoint(oldX,oldY), QSize(1,1)) #grow bounding box self.bb.setLeft( min(self.bb.left(), max(0, x-self.brushSize/2-1) ) ) self.bb.setRight( max(self.bb.right(), min(self.sliceRect[0]-1, x+self.brushSize/2+1) ) ) self.bb.setTop( min(self.bb.top(), max(0, y-self.brushSize/2-1) ) ) self.bb.setBottom(max(self.bb.bottom(), min(self.sliceRect[1]-1, y+self.brushSize/2+1) ) ) #update/move position self.pos = pos
def __paintEventNoStyle(self): p = QPainter(self) opt = QStyleOptionToolButton() self.initStyleOption(opt) fm = QFontMetrics(opt.font) palette = opt.palette # highlight brush is used as the background for the icon and background # when the tab is expanded and as mouse hover color (lighter). brush_highlight = palette.highlight() if opt.state & QStyle.State_Sunken: # State 'down' pressed during a mouse press (slightly darker). background_brush = brush_darker(brush_highlight, 110) elif opt.state & QStyle.State_MouseOver: background_brush = brush_darker(brush_highlight, 95) elif opt.state & QStyle.State_On: background_brush = brush_highlight else: # The default button brush. background_brush = palette.button() rect = opt.rect icon = opt.icon icon_size = opt.iconSize # TODO: add shift for pressed as set by the style (PM_ButtonShift...) pm = None if not icon.isNull(): if opt.state & QStyle.State_Enabled: mode = QIcon.Normal else: mode = QIcon.Disabled pm = opt.icon.pixmap( rect.size().boundedTo(icon_size), mode, QIcon.On if opt.state & QStyle.State_On else QIcon.Off) icon_area_rect = QRect(rect) icon_area_rect.setRight(int(icon_area_rect.height() * 1.26)) text_rect = QRect(rect) text_rect.setLeft(icon_area_rect.right() + 10) # Background (TODO: Should the tab button have native # toolbutton shape, drawn using PE_PanelButtonTool or even # QToolBox tab shape) # Default outline pen pen = QPen(palette.color(QPalette.Mid)) p.save() p.setPen(Qt.NoPen) p.setBrush(QBrush(background_brush)) p.drawRect(rect) # Draw the background behind the icon if the background_brush # is different. if not opt.state & QStyle.State_On: p.setBrush(brush_highlight) p.drawRect(icon_area_rect) # Line between the icon and text p.setPen(pen) p.drawLine(icon_area_rect.topRight(), icon_area_rect.bottomRight()) if opt.state & QStyle.State_HasFocus: # Set the focus frame pen and draw the border pen = QPen(QColor(FOCUS_OUTLINE_COLOR)) p.setPen(pen) p.setBrush(Qt.NoBrush) # Adjust for pen rect = rect.adjusted(0, 0, -1, -1) p.drawRect(rect) else: p.setPen(pen) # Draw the top/bottom border if self.position == QStyleOptionToolBoxV2.OnlyOneTab or \ self.position == QStyleOptionToolBoxV2.Beginning or \ self.selected & \ QStyleOptionToolBoxV2.PreviousIsSelected: p.drawLine(rect.topLeft(), rect.topRight()) p.drawLine(rect.bottomLeft(), rect.bottomRight()) p.restore() p.save() text = fm.elidedText(opt.text, Qt.ElideRight, text_rect.width()) p.setPen(QPen(palette.color(QPalette.ButtonText))) p.setFont(opt.font) p.drawText(text_rect, int(Qt.AlignVCenter | Qt.AlignLeft) | \ int(Qt.TextSingleLine), text) if pm: pm_rect = QRect(QPoint(0, 0), pm.size()) centered_rect = QRect(pm_rect) centered_rect.moveCenter(icon_area_rect.center()) p.drawPixmap(centered_rect, pm, pm_rect) p.restore()
def paint(self, painter, option, index): self.initStyleOption(option, index) if hasattr(option, "checkState"): if option.checkState == Qt.Unchecked: option.checkState = Qt.PartiallyChecked elif option.checkState == Qt.PartiallyChecked: option.checkState = Qt.Unchecked elif option.checkState == Qt.Checked: option.font = QFont(option.font) option.font.setStrikeOut(True) # ref: qt4-x11-4.6.2/src/gui/styles/qcommonstyle.cpp painter.save() painter.setClipRect(option.rect) # QApplication.style().drawControl( # QStyle.CE_ItemViewItem, option, painter, # getattr(option, "widget", None)) style = QApplication.style() widget = getattr(option, "widget", None) # log.debug("widget: %r style: %r" % (widget, style.metaObject().className())) style.drawPrimitive( QStyle.PE_PanelItemViewItem, option, painter, widget) if option.checkState == Qt.Checked: painter.setOpacity(0.3) text_rect = style.subElementRect( QStyle.SE_ItemViewItemText, option, widget) item_text = option.fontMetrics.elidedText( option.text, option.textElideMode, text_rect.width()) painter.setFont(option.font) style.drawItemText(painter, text_rect, option.displayAlignment, option.palette, True, item_text, QPalette.Text) check_rect = style.subElementRect( QStyle.SE_ItemViewItemCheckIndicator, option, widget) if option.checkState == Qt.PartiallyChecked: brush = option.palette.brush(QPalette.Base) painter.fillRect(check_rect, brush) bullet_rect = QRect(check_rect) if bullet_rect.width() > BULLET_SIZE: bullet_rect.setLeft( bullet_rect.left() + (bullet_rect.width() - BULLET_SIZE) / 2) bullet_rect.setWidth(BULLET_SIZE) if bullet_rect.height() > BULLET_SIZE: bullet_rect.setTop( bullet_rect.top() + (bullet_rect.height() - BULLET_SIZE) / 2) bullet_rect.setHeight(BULLET_SIZE) painter.setPen(QPen(option.palette.color(QPalette.Text))) painter.setBrush(option.palette.brush(QPalette.Text)) painter.drawEllipse(bullet_rect) else: check_opt = QStyleOptionButton() check_opt.rect = check_rect check_opt.state = option.state & ~QStyle.State_HasFocus if option.checkState == Qt.Checked: check_opt.state |= QStyle.State_On else: check_opt.state |= QStyle.State_Off style.drawPrimitive( QStyle.PE_IndicatorItemViewItemCheck, check_opt, painter, widget) painter.restore()
class ExtractRasterValue(ParentMapTool): """ Button 18. User select nodes and assign raster elevation or value """ def __init__(self, iface, settings, action, index_action): """ Class constructor """ # Call ParentMapTool constructor super(ExtractRasterValue, self).__init__(iface, settings, action, index_action) self.dragging = False # Vertex marker self.vertexMarker = QgsVertexMarker(self.canvas) self.vertexMarker.setColor(QColor(255, 25, 25)) self.vertexMarker.setIconSize(11) self.vertexMarker.setIconType(QgsVertexMarker.ICON_BOX) # or ICON_CROSS, ICON_X self.vertexMarker.setPenWidth(5) # Rubber band self.rubberBand = QgsRubberBand(self.canvas, True) mFillColor = QColor(100, 0, 0) self.rubberBand.setColor(mFillColor) self.rubberBand.setWidth(3) mBorderColor = QColor(254, 58, 29) self.rubberBand.setBorderColor(mBorderColor) # Select rectangle self.selectRect = QRect() # Init self.vectorLayer = None self.rasterLayer = None def reset(self): """ Clear selected features """ layer = self.vectorLayer if layer is not None: layer.removeSelection() # Graphic elements self.rubberBand.reset() def set_config_action(self, action_99): """ Get the config form action""" self.configAction = action_99 """ QgsMapTools inherited event functions """ def canvasMoveEvent(self, event): """ With left click the digitizing is finished """ if self.vectorLayer is None: return if event.buttons() == Qt.LeftButton: if not self.dragging: self.dragging = True self.selectRect.setTopLeft(event.pos()) self.selectRect.setBottomRight(event.pos()) self.set_rubber_band() else: # Hide highlight self.vertexMarker.hide() # Get the click x = event.pos().x() y = event.pos().y() eventPoint = QPoint(x, y) # Snapping (retval, result) = self.snapper.snapToBackgroundLayers(eventPoint) # @UnusedVariable # That's the snapped point if result <> []: # Check Arc or Node for snapPoint in result: if snapPoint.layer == self.vectorLayer: # Get the point point = QgsPoint(result[0].snappedVertex) # Add marker self.vertexMarker.setCenter(point) self.vertexMarker.show() break def canvasPressEvent(self, event): self.selectRect.setRect(0, 0, 0, 0) self.rubberBand.reset() def canvasReleaseEvent(self, event): """ With left click the digitizing is finished """ if event.button() == Qt.LeftButton: # Get the click x = event.pos().x() y = event.pos().y() eventPoint = QPoint(x, y) # Node layer layer = self.vectorLayer # Not dragging, just simple selection if not self.dragging: # Snap to node (retval, result) = self.snapper.snapToBackgroundLayers(eventPoint) # @UnusedVariable # That's the snapped point if result <> [] and (result[0].layer.name() == self.vectorLayer.name()): point = QgsPoint(result[0].snappedVertex) # @UnusedVariable layer.removeSelection() layer.select([result[0].snappedAtGeometry]) # Interpolate values self.raster_interpolate() # Hide highlight self.vertexMarker.hide() else: # Set valid values for rectangle's width and height if self.selectRect.width() == 1: self.selectRect.setLeft(self.selectRect.left() + 1) if self.selectRect.height() == 1: self.selectRect.setBottom(self.selectRect.bottom() + 1) self.set_rubber_band() selectGeom = self.rubberBand.asGeometry() # @UnusedVariable self.select_multiple_features(self.selectRectMapCoord) self.dragging = False # Interpolate values self.raster_interpolate() elif event.button() == Qt.RightButton: # Interpolate values self.raster_interpolate() def activate(self): # Check button self.action().setChecked(True) # Rubber band self.rubberBand.reset() # Store user snapping configuration self.snapperManager.storeSnappingOptions() # Clear snapping self.snapperManager.clearSnapping() # Get layers res = self.find_raster_layers() # if res == 0: # self.controller.show_warning("Raster configuration tool not properly configured.") # return # Change cursor self.canvas.setCursor(self.cursor) # Show help message when action is activated if self.show_help: message = ( "Right click to use current selection, select connec points by clicking or dragging (selection box)" ) self.controller.show_info(message, context_name="ui_message") # Control current layer (due to QGIS bug in snapping system) try: if self.canvas.currentLayer().type() == QgsMapLayer.VectorLayer: self.canvas.setCurrentLayer(self.layer_arc) except: self.canvas.setCurrentLayer(self.layer_arc) def deactivate(self): # Check button self.action().setChecked(False) # Rubber band self.rubberBand.reset() # Restore previous snapping self.snapperManager.recoverSnappingOptions() # Recover cursor self.canvas.setCursor(self.stdCursor) def nearestNeighbor(self, thePoint): ident = self.dataProv.identify(thePoint, QgsRaster.IdentifyFormatValue) value = None if ident is not None: # and ident.has_key(choosenBand+1): try: value = float(ident.results()[int(self.band)]) except TypeError: value = None if value == self.noDataValue: return None return value def writeInterpolation(self, f, fieldIdx): thePoint = f.geometry().asPoint() value = self.nearestNeighbor(thePoint) self.vectorLayer.changeAttributeValue(f.id(), fieldIdx, value) def raster_interpolate(self): """ Interpolate features value from raster """ # Interpolate values if self.vectorLayer is None and self.rasterLayer is None: return # Get data provider layer = self.vectorLayer self.dataProv = self.rasterLayer.dataProvider() if self.dataProv.srcNoDataValue(int(self.band)): self.noDataValue = self.dataProv.srcNoDataValue(int(self.band)) else: self.noDataValue = None self.continueProcess = True self.fieldIdx = "" self.fieldIdx = layer.fieldNameIndex(self.fieldName) if self.band == 0: self.controller.show_warning("You must choose a band for the raster layer.") return if self.fieldName == "": self.controller.show_warning("You must choose a field to write values.") return if self.fieldIdx < 0: self.controller.show_warning("Selected field does not exist in feature layer.") return k = 0 c = 0 f = QgsFeature() # Check features selected if layer.selectedFeatureCount() == 0: message = "You have to select at least one feature!" self.controller.show_warning(message, context_name="ui_message") return # Check editable if not layer.isEditable(): layer.startEditing() # Get selected id's ids = self.vectorLayer.selectedFeaturesIds() for fid in ids: k += 1 layer.getFeatures(QgsFeatureRequest(fid)).nextFeature(f) c += 1 self.writeInterpolation(f, self.fieldIdx) QCoreApplication.processEvents() self.controller.show_info( "%u values have been updated in layer %s.%s over %u points using %s raster" % (c, self.vectorLayer.name(), self.fieldName, k, self.table_raster) ) # Check editable if layer.isEditable(): layer.commitChanges() # Refresh map canvas self.rubberBand.reset() self.iface.mapCanvas().refresh() def set_rubber_band(self): # Coordinates transform transform = self.canvas.getCoordinateTransform() # Coordinates ll = transform.toMapCoordinates(self.selectRect.left(), self.selectRect.bottom()) lr = transform.toMapCoordinates(self.selectRect.right(), self.selectRect.bottom()) ul = transform.toMapCoordinates(self.selectRect.left(), self.selectRect.top()) ur = transform.toMapCoordinates(self.selectRect.right(), self.selectRect.top()) # Rubber band self.rubberBand.reset() self.rubberBand.addPoint(ll, False) self.rubberBand.addPoint(lr, False) self.rubberBand.addPoint(ur, False) self.rubberBand.addPoint(ul, False) self.rubberBand.addPoint(ll, True) self.selectRectMapCoord = QgsRectangle(ll, ur) def select_multiple_features(self, selectGeometry): # Default choice behaviour = QgsVectorLayer.SetSelection # Modifiers modifiers = QApplication.keyboardModifiers() if modifiers == Qt.ControlModifier: behaviour = QgsVectorLayer.AddToSelection elif modifiers == Qt.ShiftModifier: behaviour = QgsVectorLayer.RemoveFromSelection if self.vectorLayer is None: return # Change cursor QApplication.setOverrideCursor(Qt.WaitCursor) # Selection self.vectorLayer.selectByRect(selectGeometry, behaviour) # Old cursor QApplication.restoreOverrideCursor() def find_raster_layers(self): # Query database (form data) sql = "SELECT *" sql += " FROM " + self.schema_name + ".config_extract_raster_value" rows = self.controller.get_rows(sql) if not rows: self.controller.show_warning("Any data found in table config_extract_raster_value") self.configAction.activate(QAction.Trigger) return 0 # Layers row = rows[0] self.table_raster = row[1] self.band = row[2] self.table_vector = row[3] self.fieldName = row[4] # Check if we have any layer loaded layers = self.iface.legendInterface().layers() if len(layers) == 0: return # Init layers self.rasterLayer = None self.vectorLayer = None # Iterate over all layers to get the ones specified in 'db' config section for cur_layer in layers: if cur_layer.name() == self.table_raster: self.rasterLayer = cur_layer (uri_schema, uri_table) = self.controller.get_layer_source(cur_layer) # @UnusedVariable if uri_table is not None: if self.table_vector in uri_table: self.vectorLayer = cur_layer # Check config if self.vectorLayer is None or self.rasterLayer is None: self.configAction.activate(QAction.Trigger) # Set snapping if self.vectorLayer <> None: self.snapperManager.snapToLayer(self.vectorLayer) else: self.controller.show_warning("Check vector_layer in config form, layer does not exist or is not defined.") return 0 if self.rasterLayer == None: self.controller.show_warning("Check raster_layer in config form, layer does not exist or is not defined.") return 0 return 1
class ConnecMapTool(ParentMapTool): """ Button 20. User select connections from layer 'connec' Execute SQL function: 'gw_fct_connect_to_network' """ def __init__(self, iface, settings, action, index_action): """ Class constructor """ # Call ParentMapTool constructor super(ConnecMapTool, self).__init__(iface, settings, action, index_action) self.dragging = False # Vertex marker self.vertexMarker = QgsVertexMarker(self.canvas) self.vertexMarker.setColor(QColor(255, 25, 25)) self.vertexMarker.setIconSize(11) self.vertexMarker.setIconType(QgsVertexMarker.ICON_BOX) # or ICON_CROSS, ICON_X self.vertexMarker.setPenWidth(5) # Rubber band self.rubberBand = QgsRubberBand(self.canvas, True) mFillColor = QColor(100, 0, 0) self.rubberBand.setColor(mFillColor) self.rubberBand.setWidth(3) mBorderColor = QColor(254, 58, 29) self.rubberBand.setBorderColor(mBorderColor) # Select rectangle self.selectRect = QRect() def reset(self): """ Clear selected features """ layer = self.layer_connec if layer is not None: layer.removeSelection() # Graphic elements self.rubberBand.reset() """ QgsMapTools inherited event functions """ def canvasMoveEvent(self, event): """ With left click the digitizing is finished """ if event.buttons() == Qt.LeftButton: if not self.dragging: self.dragging = True self.selectRect.setTopLeft(event.pos()) self.selectRect.setBottomRight(event.pos()) self.set_rubber_band() else: # Hide highlight self.vertexMarker.hide() # Get the click x = event.pos().x() y = event.pos().y() eventPoint = QPoint(x, y) # Snapping (retval, result) = self.snapper.snapToBackgroundLayers(eventPoint) # @UnusedVariable # That's the snapped point if result <> []: # Check Arc or Node for snapPoint in result: if snapPoint.layer == self.layer_connec: # Get the point point = QgsPoint(result[0].snappedVertex) # Add marker self.vertexMarker.setCenter(point) self.vertexMarker.show() break def canvasPressEvent(self, event): self.selectRect.setRect(0, 0, 0, 0) self.rubberBand.reset() def canvasReleaseEvent(self, event): """ With left click the digitizing is finished """ if event.button() == Qt.LeftButton: # Get the click x = event.pos().x() y = event.pos().y() eventPoint = QPoint(x, y) # Node layer layer = self.layer_connec # Not dragging, just simple selection if not self.dragging: # Snap to node (retval, result) = self.snapper.snapToBackgroundLayers(eventPoint) # @UnusedVariable # That's the snapped point if result <> [] and (result[0].layer.name() == self.layer_connec.name()): point = QgsPoint(result[0].snappedVertex) # @UnusedVariable layer.removeSelection() layer.select([result[0].snappedAtGeometry]) # Create link self.link_connec() # Hide highlight self.vertexMarker.hide() else: # Set valid values for rectangle's width and height if self.selectRect.width() == 1: self.selectRect.setLeft(self.selectRect.left() + 1) if self.selectRect.height() == 1: self.selectRect.setBottom(self.selectRect.bottom() + 1) self.set_rubber_band() selectGeom = self.rubberBand.asGeometry() # @UnusedVariable self.select_multiple_features(self.selectRectMapCoord) self.dragging = False # Create link self.link_connec() elif event.button() == Qt.RightButton: # Create link self.link_connec() def activate(self): # Check button self.action().setChecked(True) # Rubber band self.rubberBand.reset() # Store user snapping configuration self.snapperManager.storeSnappingOptions() # Clear snapping self.snapperManager.clearSnapping() # Set snapping to arc and node self.snapperManager.snapToConnec() # Change cursor self.canvas.setCursor(self.cursor) # Show help message when action is activated if self.show_help: message = ( "Right click to use current selection, select connec points by clicking or dragging (selection box)" ) self.controller.show_info(message, context_name="ui_message") # Control current layer (due to QGIS bug in snapping system) try: if self.canvas.currentLayer().type() == QgsMapLayer.VectorLayer: self.canvas.setCurrentLayer(self.layer_connec) except: self.canvas.setCurrentLayer(self.layer_connec) def deactivate(self): # Check button self.action().setChecked(False) # Rubber band self.rubberBand.reset() # Restore previous snapping self.snapperManager.recoverSnappingOptions() # Recover cursor self.canvas.setCursor(self.stdCursor) def link_connec(self): """ Link selected connec to the pipe """ # Get selected features (from layer 'connec') aux = "{" layer = self.layer_connec if layer.selectedFeatureCount() == 0: message = "You have to select at least one feature!" self.controller.show_warning(message, context_name="ui_message") return features = layer.selectedFeatures() for feature in features: connec_id = feature.attribute("connec_id") aux += str(connec_id) + ", " connec_array = aux[:-2] + "}" # Execute function function_name = "gw_fct_connect_to_network" sql = "SELECT " + self.schema_name + "." + function_name + "('" + connec_array + "');" self.controller.execute_sql(sql) # Refresh map canvas self.rubberBand.reset() self.iface.mapCanvas().refresh() def set_rubber_band(self): # Coordinates transform transform = self.canvas.getCoordinateTransform() # Coordinates ll = transform.toMapCoordinates(self.selectRect.left(), self.selectRect.bottom()) lr = transform.toMapCoordinates(self.selectRect.right(), self.selectRect.bottom()) ul = transform.toMapCoordinates(self.selectRect.left(), self.selectRect.top()) ur = transform.toMapCoordinates(self.selectRect.right(), self.selectRect.top()) # Rubber band self.rubberBand.reset() self.rubberBand.addPoint(ll, False) self.rubberBand.addPoint(lr, False) self.rubberBand.addPoint(ur, False) self.rubberBand.addPoint(ul, False) self.rubberBand.addPoint(ll, True) self.selectRectMapCoord = QgsRectangle(ll, ur) def select_multiple_features(self, selectGeometry): # Default choice behaviour = QgsVectorLayer.SetSelection # Modifiers modifiers = QApplication.keyboardModifiers() if modifiers == Qt.ControlModifier: behaviour = QgsVectorLayer.AddToSelection elif modifiers == Qt.ShiftModifier: behaviour = QgsVectorLayer.RemoveFromSelection if self.layer_connec is None: return # Change cursor QApplication.setOverrideCursor(Qt.WaitCursor) # Selection self.layer_connec.selectByRect(selectGeometry, behaviour) # Old cursor QApplication.restoreOverrideCursor()