def exportAsPdf(self): self.repaintModel(controls=False) filename, fileFilter = QFileDialog.getSaveFileName( self, self.tr('Save Model As PDF'), '', self.tr('PDF files (*.pdf *.PDF)')) if not filename: return if not filename.lower().endswith('.pdf'): filename += '.pdf' totalRect = self.scene.itemsBoundingRect() totalRect.adjust(-10, -10, 10, 10) printerRect = QRectF(0, 0, totalRect.width(), totalRect.height()) printer = QPrinter() printer.setOutputFormat(QPrinter.PdfFormat) printer.setOutputFileName(filename) printer.setPaperSize(QSizeF(printerRect.width(), printerRect.height()), QPrinter.DevicePixel) printer.setFullPage(True) painter = QPainter(printer) self.scene.render(painter, printerRect, totalRect) painter.end() self.bar.pushMessage( "", self.tr( "Successfully exported model as PDF to <a href=\"{}\">{}</a>"). format( QUrl.fromLocalFile(filename).toString(), QDir.toNativeSeparators(filename)), level=Qgis.Success, duration=5) self.repaintModel(controls=True)
def add_data_row(self, data, title, uom, station_name = None): plot_item = PlotItem(size=QSizeF(self.__scene.width(), self.DEFAULT_ROW_HEIGHT), render_type = POINT_RENDERER, x_orientation = ORIENTATION_LEFT_TO_RIGHT, y_orientation = ORIENTATION_UPWARD) plot_item.set_layer(data.get_layer()) plot_item.tooltipRequested.connect(lambda txt:self.on_plot_tooltip(station_name, txt)) legend_item = LegendItem(self.DEFAULT_ROW_HEIGHT, title, unit_of_measure=uom, is_vertical=True) data.data_modified.connect(lambda data=data : self._update_data_row(data)) if self._min_x is None: self._min_x, self._max_x = data.get_x_min(), data.get_x_max() # if we have only one value, center it on a 2 minutes range if self._min_x == self._max_x: self._min_x -= 60 self._max_x += 60 self.add_time_scale() self.__data2logitems[data] = (plot_item, legend_item) self._add_row(plot_item, legend_item) self._update_data_row(data) self._update_row_depths()
def testHtmlAnnotationWithFeature(self): """ test rendering a html annotation with a feature""" layer = QgsVectorLayer( "Point?crs=EPSG:3111&field=station:string&field=suburb:string", 'test', "memory") a = QgsHtmlAnnotation() a.fillSymbol().symbolLayer(0).setStrokeColor(QColor(0, 0, 0)) a.markerSymbol().symbolLayer(0).setStrokeColor(QColor(0, 0, 0)) a.setFrameSizeMm(QSizeF(400 / 3.7795275, 250 / 3.7795275)) a.setFrameOffsetFromReferencePointMm( QPointF(70 / 3.7795275, 90 / 3.7795275)) a.setMapLayer(layer) html = TEST_DATA_DIR + "/test_html_feature.html" a.setSourceFile(html) im = self.renderAnnotation(a, QPointF(20, 30)) self.assertTrue(self.imageCheck('html_nofeature', 'html_nofeature', im)) f = QgsFeature(layer.fields()) f.setValid(True) f.setAttributes(['hurstbridge', 'somewhere']) a.setAssociatedFeature(f) im = self.renderAnnotation(a, QPointF(20, 30)) self.assertTrue(self.imageCheck('html_feature', 'html_feature', im))
def testSettingFeature(self): """ test that feature is set when item moves """ a = QgsTextAnnotation() a.setFrameSize(QSizeF(300, 200)) a.setFrameOffsetFromReferencePoint(QPointF(40, 50)) a.setHasFixedMapPosition(True) a.setMapPosition(QgsPointXY(12, 34)) a.setMapPositionCrs(QgsCoordinateReferenceSystem(4326)) canvas = QgsMapCanvas() canvas.setDestinationCrs(QgsCoordinateReferenceSystem(4326)) canvas.setFrameStyle(0) canvas.resize(600, 400) canvas.setExtent(QgsRectangle(10, 30, 20, 35)) i = QgsMapCanvasAnnotationItem(a, canvas) # NOQA layer = QgsVectorLayer( "Point?crs=EPSG:4326&field=station:string&field=suburb:string", 'test', "memory") canvas.setLayers([layer]) f = QgsFeature(layer.fields()) f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(14, 31))) f.setValid(True) f.setAttributes(['hurstbridge', 'somewhere']) self.assertTrue(layer.dataProvider().addFeatures([f])) a.setMapLayer(layer) self.assertFalse(a.associatedFeature().isValid()) a.setMapPosition(QgsPointXY(14, 31)) self.assertTrue(a.associatedFeature().isValid()) self.assertEqual(a.associatedFeature().attributes()[0], 'hurstbridge') a.setMapPosition(QgsPointXY(17, 31)) self.assertFalse(a.associatedFeature().isValid())
def testPlot(self): plot = Qgs2DPlot() plot.setSize(QSizeF(600, 500)) sym1 = QgsFillSymbol.createSimple({ 'color': '#fdbf6f', 'outline_style': 'no' }) plot.setChartBackgroundSymbol(sym1) sym2 = QgsFillSymbol.createSimple({ 'outline_color': '#0000ff', 'style': 'no', 'outline_style': 'solid', 'outline_width': 1 }) plot.setChartBorderSymbol(sym2) sym3 = QgsLineSymbol.createSimple({ 'outline_color': '#00ffff', 'outline_width': 1 }) plot.xAxis().setGridMajorSymbol(sym3) sym4 = QgsLineSymbol.createSimple({ 'outline_color': '#ff00ff', 'outline_width': 0.5 }) plot.xAxis().setGridMinorSymbol(sym4) sym3 = QgsLineSymbol.createSimple({ 'outline_color': '#0066ff', 'outline_width': 1 }) plot.yAxis().setGridMajorSymbol(sym3) sym4 = QgsLineSymbol.createSimple({ 'outline_color': '#ff4433', 'outline_width': 0.5 }) plot.yAxis().setGridMinorSymbol(sym4) font = QgsFontUtils.getStandardTestFont('Bold', 16) x_axis_format = QgsTextFormat.fromQFont(font) x_axis_format.setColor(QColor(255, 0, 0)) plot.xAxis().setTextFormat(x_axis_format) x_axis_number_format = QgsBasicNumericFormat() x_axis_number_format.setNumberDecimalPlaces(1) x_axis_number_format.setShowTrailingZeros(True) plot.xAxis().setNumericFormat(x_axis_number_format) font = QgsFontUtils.getStandardTestFont('Bold', 18) y_axis_format = QgsTextFormat.fromQFont(font) y_axis_format.setColor(QColor(0, 255, 0)) plot.yAxis().setTextFormat(y_axis_format) y_axis_number_format = QgsBasicNumericFormat() y_axis_number_format.setShowPlusSign(True) plot.yAxis().setNumericFormat(y_axis_number_format) plot.setXMinimum(3) plot.setXMaximum(9) plot.setYMinimum(2) plot.setYMaximum(12) im = QImage(600, 500, QImage.Format_ARGB32) im.fill(Qt.white) im.setDotsPerMeterX(int(96 / 25.4 * 1000)) im.setDotsPerMeterY(int(96 / 25.4 * 1000)) painter = QPainter(im) rc = QgsRenderContext.fromQPainter(painter) plot.render(rc) painter.end() assert self.imageCheck('plot_2d_base', 'plot_2d_base', im) plot_rect = plot.interiorPlotArea(rc) self.assertAlmostEqual(plot_rect.left(), 64.8, 0) self.assertAlmostEqual(plot_rect.right(), 592.44, 0) self.assertAlmostEqual(plot_rect.top(), 7.559, 0) self.assertAlmostEqual(plot_rect.bottom(), 465.55, 0)
def testOptimiseIntervals(self): plot = Qgs2DPlot() plot.setSize(QSizeF(600, 500)) font = QgsFontUtils.getStandardTestFont('Bold', 16) x_axis_format = QgsTextFormat.fromQFont(font) plot.xAxis().setTextFormat(x_axis_format) font = QgsFontUtils.getStandardTestFont('Bold', 18) y_axis_format = QgsTextFormat.fromQFont(font) plot.yAxis().setTextFormat(y_axis_format) plot.setXMinimum(3) plot.setXMaximum(13) plot.setYMinimum(2) plot.setYMaximum(12) im = QImage(600, 500, QImage.Format_ARGB32) im.fill(Qt.white) im.setDotsPerMeterX(int(96 / 25.4 * 1000)) im.setDotsPerMeterY(int(96 / 25.4 * 1000)) painter = QPainter(im) rc = QgsRenderContext.fromQPainter(painter) painter.end() plot.calculateOptimisedIntervals(rc) self.assertEqual(plot.xAxis().labelInterval(), 1) self.assertEqual(plot.yAxis().labelInterval(), 2) self.assertEqual(plot.xAxis().gridIntervalMinor(), 1) self.assertEqual(plot.yAxis().gridIntervalMinor(), 1) self.assertEqual(plot.xAxis().gridIntervalMajor(), 5) self.assertEqual(plot.yAxis().gridIntervalMajor(), 4) plot.setXMinimum(3) plot.setXMaximum(113) plot.setYMinimum(2) plot.setYMaximum(112) plot.calculateOptimisedIntervals(rc) self.assertEqual(plot.xAxis().labelInterval(), 20) self.assertEqual(plot.yAxis().labelInterval(), 20) self.assertEqual(plot.xAxis().gridIntervalMinor(), 10) self.assertEqual(plot.yAxis().gridIntervalMinor(), 10) self.assertEqual(plot.xAxis().gridIntervalMajor(), 40) self.assertEqual(plot.yAxis().gridIntervalMajor(), 40) plot.setXMinimum(0.3) plot.setXMaximum(0.5) plot.setYMinimum(1.1) plot.setYMaximum(2) plot.calculateOptimisedIntervals(rc) self.assertEqual(plot.xAxis().labelInterval(), 0.05) self.assertEqual(plot.yAxis().labelInterval(), 0.2) self.assertEqual(plot.xAxis().gridIntervalMinor(), 0.025) self.assertEqual(plot.yAxis().gridIntervalMinor(), 0.1) self.assertEqual(plot.xAxis().gridIntervalMajor(), 0.1) self.assertEqual(plot.yAxis().gridIntervalMajor(), 0.4) plot.setXMinimum(-10) plot.setXMaximum(0) plot.setYMinimum(-10000) plot.setYMaximum(-500) plot.calculateOptimisedIntervals(rc) self.assertEqual(plot.xAxis().labelInterval(), 2) self.assertEqual(plot.yAxis().labelInterval(), 2000) self.assertEqual(plot.xAxis().gridIntervalMinor(), 1) self.assertEqual(plot.yAxis().gridIntervalMinor(), 1000) self.assertEqual(plot.xAxis().gridIntervalMajor(), 4) self.assertEqual(plot.yAxis().gridIntervalMajor(), 4000) plot.setXMinimum(100000) plot.setXMaximum(200000) plot.calculateOptimisedIntervals(rc) self.assertEqual(plot.xAxis().labelInterval(), 100000) self.assertEqual(plot.xAxis().gridIntervalMinor(), 50000) self.assertEqual(plot.xAxis().gridIntervalMajor(), 200000)
def testPlotDataDefinedProperties(self): plot = Qgs2DPlot() plot.setSize(QSizeF(600, 500)) sym1 = QgsFillSymbol.createSimple({ 'color': '#ffffff', 'outline_style': 'no' }) plot.setChartBackgroundSymbol(sym1) sym2 = QgsFillSymbol.createSimple({ 'outline_color': '#000000', 'style': 'no', 'outline_style': 'solid', 'outline_width': 1 }) plot.setChartBorderSymbol(sym2) sym3 = QgsLineSymbol.createSimple({ 'outline_color': '#00ffff', 'outline_width': 1, 'capstyle': 'flat' }) sym3[0].setDataDefinedProperty( QgsSymbolLayer.PropertyStrokeWidth, QgsProperty.fromExpression( 'case when @plot_axis_value = 10 then 3 else 1 end')) plot.xAxis().setGridMajorSymbol(sym3) sym4 = QgsLineSymbol.createSimple({ 'outline_color': '#ff00ff', 'outline_width': 0.5, 'capstyle': 'flat' }) sym4[0].setDataDefinedProperty( QgsSymbolLayer.PropertyStrokeWidth, QgsProperty.fromExpression( 'case when @plot_axis_value = 6 then 3 else 0.5 end')) plot.xAxis().setGridMinorSymbol(sym4) sym3 = QgsLineSymbol.createSimple({ 'outline_color': '#0066ff', 'outline_width': 1, 'capstyle': 'flat' }) sym3[0].setDataDefinedProperty( QgsSymbolLayer.PropertyStrokeWidth, QgsProperty.fromExpression( 'case when @plot_axis_value = 5 then 3 else 0.5 end')) plot.yAxis().setGridMajorSymbol(sym3) sym4 = QgsLineSymbol.createSimple({ 'outline_color': '#ff4433', 'outline_width': 0.5, 'capstyle': 'flat' }) sym4[0].setDataDefinedProperty( QgsSymbolLayer.PropertyStrokeWidth, QgsProperty.fromExpression( 'case when @plot_axis_value = 9 then 3 else 0.5 end')) plot.yAxis().setGridMinorSymbol(sym4) font = QgsFontUtils.getStandardTestFont('Bold', 16) x_axis_format = QgsTextFormat.fromQFont(font) x_axis_format.dataDefinedProperties().setProperty( QgsPalLayerSettings.Color, QgsProperty.fromExpression( 'case when @plot_axis_value %3 = 0 then \'#ff0000\' else \'#000000\' end' )) plot.xAxis().setTextFormat(x_axis_format) font = QgsFontUtils.getStandardTestFont('Bold', 18) y_axis_format = QgsTextFormat.fromQFont(font) y_axis_format.dataDefinedProperties().setProperty( QgsPalLayerSettings.Color, QgsProperty.fromExpression( 'case when @plot_axis_value %4 = 0 then \'#0000ff\' else \'#000000\' end' )) plot.yAxis().setTextFormat(y_axis_format) plot.setXMinimum(3) plot.setXMaximum(13) plot.setYMinimum(2) plot.setYMaximum(12) im = QImage(600, 500, QImage.Format_ARGB32) im.fill(Qt.white) im.setDotsPerMeterX(int(96 / 25.4 * 1000)) im.setDotsPerMeterY(int(96 / 25.4 * 1000)) painter = QPainter(im) rc = QgsRenderContext.fromQPainter(painter) plot.render(rc) painter.end() assert self.imageCheck('plot_2d_data_defined', 'plot_2d_data_defined', im) plot_rect = plot.interiorPlotArea(rc) self.assertAlmostEqual(plot_rect.left(), 44.71, 0) self.assertAlmostEqual(plot_rect.right(), 592.44, 0) self.assertAlmostEqual(plot_rect.top(), 7.559, 0) self.assertAlmostEqual(plot_rect.bottom(), 465.55, 0)
def testPlotIntervals(self): plot = Qgs2DPlot() plot.setSize(QSizeF(600, 500)) sym1 = QgsFillSymbol.createSimple({ 'color': '#fdbf6f', 'outline_style': 'no' }) plot.setChartBackgroundSymbol(sym1) sym2 = QgsFillSymbol.createSimple({ 'outline_color': '#0000ff', 'style': 'no', 'outline_style': 'solid', 'outline_width': 1 }) plot.setChartBorderSymbol(sym2) sym3 = QgsLineSymbol.createSimple({ 'outline_color': '#00ffff', 'outline_width': 1 }) plot.xAxis().setGridMajorSymbol(sym3) sym4 = QgsLineSymbol.createSimple({ 'outline_color': '#ff00ff', 'outline_width': 0.5 }) plot.xAxis().setGridMinorSymbol(sym4) sym3 = QgsLineSymbol.createSimple({ 'outline_color': '#0066ff', 'outline_width': 1 }) plot.yAxis().setGridMajorSymbol(sym3) sym4 = QgsLineSymbol.createSimple({ 'outline_color': '#ff4433', 'outline_width': 0.5 }) plot.yAxis().setGridMinorSymbol(sym4) font = QgsFontUtils.getStandardTestFont('Bold', 16) x_axis_format = QgsTextFormat.fromQFont(font) plot.xAxis().setTextFormat(x_axis_format) font = QgsFontUtils.getStandardTestFont('Bold', 18) y_axis_format = QgsTextFormat.fromQFont(font) plot.yAxis().setTextFormat(y_axis_format) plot.setXMinimum(1) plot.setXMaximum(21) plot.setYMinimum(27) plot.setYMaximum(327) plot.xAxis().setGridIntervalMajor(10) plot.xAxis().setGridIntervalMinor(2) plot.yAxis().setGridIntervalMajor(100) plot.yAxis().setGridIntervalMinor(50) plot.xAxis().setLabelInterval(5) plot.yAxis().setLabelInterval(70) im = QImage(600, 500, QImage.Format_ARGB32) im.fill(Qt.white) im.setDotsPerMeterX(int(96 / 25.4 * 1000)) im.setDotsPerMeterY(int(96 / 25.4 * 1000)) painter = QPainter(im) rc = QgsRenderContext.fromQPainter(painter) plot.render(rc) painter.end() assert self.imageCheck('plot_2d_intervals', 'plot_2d_intervals', im)
class PointRotationItem(QgsMapCanvasItem): """ A map canvas item which shows an angle display and preview of marker rotation """ def __init__(self, canvas): super().__init__(canvas) self.rotation = 0 self.pixmap = QPixmap() self.item_size = QSizeF() self.marker_font = QFont() self.marker_font.setPointSize(12) self.marker_font.setBold(True) self.arrow_path = QPainterPath() im = QImage(24, 24, QImage.Format_ARGB32) im.fill(Qt.transparent) self.set_symbol(im) def paint(self, painter, option, widget): if not painter: return painter.save() painter.setRenderHint(QPainter.Antialiasing, True) # do a bit of trigonometry to find out how to transform a rotated item such # that the center point is at the point feature x = 0.0 y = 0.0 if self.pixmap.width() > 0 and self.pixmap.height() > 0: half_item_diagonal = math.sqrt( self.pixmap.width() * self.pixmap.width() + self.pixmap.height() * self.pixmap.height()) / 2 diagonal_angle = math.acos( self.pixmap.width() / (half_item_diagonal * 2)) * 180 / math.pi x = half_item_diagonal * math.cos( (self.rotation - diagonal_angle) * math.pi / 180) y = half_item_diagonal * math.sin( (self.rotation - diagonal_angle) * math.pi / 180) painter.rotate(self.rotation) painter.translate(x - self.pixmap.width() / 2.0, -y - self.pixmap.height() / 2.0) painter.drawPixmap(0, 0, self.pixmap) # draw arrow, using a red line over a thicker white line so that the arrow is visible # against a range of backgrounds pen = QPen() pen.setWidth(GuiUtils.scale_icon_size(4)) pen.setColor(QColor(Qt.white)) painter.setPen(pen) painter.drawPath(self.arrow_path) pen.setWidth(GuiUtils.scale_icon_size(1)) pen.setColor(QColor(Qt.red)) painter.setPen(pen) painter.drawPath(self.arrow_path) painter.restore() # draw numeric value beside the symbol painter.save() painter.setRenderHint(QPainter.Antialiasing, True) buffer_pen = QPen() buffer_pen.setColor(Qt.white) buffer_pen.setWidthF(GuiUtils.scale_icon_size(4)) fm = QFontMetricsF(self.marker_font) label = QPainterPath() label.addText(self.pixmap.width(), self.pixmap.height() / 2.0 + fm.height() / 2.0, self.marker_font, str(round(self.rotation, 1))) painter.setPen(buffer_pen) painter.setBrush(Qt.NoBrush) painter.drawPath(label) painter.setPen(Qt.NoPen) painter.setBrush(QBrush(Qt.black)) painter.drawPath(label) painter.restore() def set_point_location(self, p): transformed_point = self.toCanvasCoordinates(p) self.setPos(transformed_point.x() - self.pixmap.width() / 2.0, transformed_point.y() - self.pixmap.height() / 2.0) def set_symbol_rotation(self, rotation: float): self.rotation = rotation def set_symbol(self, symbol_image: QImage): self.pixmap = QPixmap.fromImage(symbol_image) fm = QFontMetricsF(self.marker_font) # set item size self.item_size.setWidth(self.pixmap.width() + fm.width("360")) pixmap_height = self.pixmap.height() font_height = fm.height() if pixmap_height >= font_height: self.item_size.setHeight(self.pixmap.height()) else: self.item_size.setHeight(fm.height()) half_item_width = self.pixmap.width() / 2.0 self.arrow_path = QPainterPath() self.arrow_path.moveTo(half_item_width, pixmap_height) self.arrow_path.lineTo(half_item_width, 0) self.arrow_path.moveTo(self.pixmap.width() * 0.25, pixmap_height * 0.25) self.arrow_path.lineTo(half_item_width, 0) self.arrow_path.lineTo(self.pixmap.width() * 0.75, pixmap_height * 0.25)
def draw(self, rows, con, args, geomType, canvasItemList, mapCanvas): ''' draw the result ''' resultPathsRubberBands = canvasItemList['paths'] rubberBand = None cur_path_id = -1 for row in rows: cur2 = con.cursor() args['result_path_id'] = row[0] args['result_source_id'] = row[1] args['result_target_id'] = row[2] args['result_cost'] = row[3] if args['result_path_id'] != cur_path_id: cur_path_id = args['result_path_id'] if rubberBand: resultPathsRubberBands.append(rubberBand) rubberBand = None rubberBand = QgsRubberBand(mapCanvas, Utils.getRubberBandType(False)) rubberBand.setColor(QColor(255, 0, 0, 128)) rubberBand.setWidth(4) if args['result_cost'] != -1: query2 = """ SELECT ST_AsText( ST_MakeLine( (SELECT the_geom FROM %(edge_table)s_vertices_pgr WHERE id = %(result_source_id)d), (SELECT the_geom FROM %(edge_table)s_vertices_pgr WHERE id = %(result_target_id)d) )) """ % args ##Utils.logMessage(query2) cur2.execute(query2) row2 = cur2.fetchone() ##Utils.logMessage(str(row2[0])) assert row2, "Invalid result geometry. (path_id:%(result_path_id)d, saource_id:%(result_source_id)d, target_id:%(result_target_id)d)" % args geom = QgsGeometry().fromWkt(str(row2[0])) if geom.wkbType() == QgsWkbTypes.MultiLineString: for line in geom.asMultiPolyline(): for pt in line: rubberBand.addPoint(pt) elif geom.wkbType() == QgsWkbTypes.LineString: for pt in geom.asPolyline(): rubberBand.addPoint(pt) if rubberBand: resultPathsRubberBands.append(rubberBand) rubberBand = None resultNodesTextAnnotations = canvasItemList['annotations'] Utils.setStartPoint(geomType, args) Utils.setEndPoint(geomType, args) for row in rows: cur2 = con.cursor() args['result_seq'] = row[0] args['result_source_id'] = row[1] args['result_target_id'] = row[2] args['result_cost'] = row[3] query2 = """ SELECT ST_AsText(%(transform_s)s%(startpoint)s%(transform_e)s) FROM %(edge_table)s WHERE %(source)s = %(result_target_id)d UNION SELECT ST_AsText(%(transform_s)s%(endpoint)s%(transform_e)s) FROM %(edge_table)s WHERE %(target)s = %(result_target_id)d """ % args cur2.execute(query2) row2 = cur2.fetchone() assert row2, "Invalid result geometry. (target_id:%(result_target_id)d)" % args geom = QgsGeometry().fromWkt(str(row2[0])) pt = geom.asPoint() textDocument = QTextDocument( "%(result_target_id)d:%(result_cost)f" % args) textAnnotation = QgsTextAnnotation() textAnnotation.setMapPosition(geom.asPoint()) textAnnotation.setFrameSize(QSizeF(textDocument.idealWidth(), 20)) textAnnotation.setFrameOffsetFromReferencePoint(QPointF(20, -40)) textAnnotation.setDocument(textDocument) QgsMapCanvasAnnotationItem(textAnnotation, mapCanvas) resultNodesTextAnnotations.append(textAnnotation)
def testFills(self): shape = QgsLegendPatchShape( QgsSymbol.Fill, QgsGeometry.fromWkt('Polygon((5 5, 1 2, 3 4, 5 5))'), False) self.assertEqual( self.polys_to_list(shape.toQPolygonF(QgsSymbol.Fill, QSizeF(1, 1))), [[[[1.0, 0.0], [0.0, 1.0], [0.5, 0.333], [1.0, 0.0]]]]) self.assertEqual( self.polys_to_list(shape.toQPolygonF(QgsSymbol.Fill, QSizeF(10, 2))), [[[[10.0, 0.0], [0.0, 2.0], [5.0, 0.667], [10.0, 0.0]]]]) # requesting different symbol type, should return default self.assertEqual( self.polys_to_list(shape.toQPolygonF(QgsSymbol.Line, QSizeF(1, 1))), [[[[0.0, 0.5], [1.0, 0.5]]]]) # rings shape = QgsLegendPatchShape( QgsSymbol.Fill, QgsGeometry.fromWkt( 'Polygon((5 5, 1 2, 3 4, 5 5), (4.5 4.5, 4.4 4.4, 4.5 4.4, 4.5 4.5))' ), False) self.assertEqual( self.polys_to_list(shape.toQPolygonF(QgsSymbol.Fill, QSizeF(1, 1))), [[[[1.0, 0.0], [0.0, 1.0], [0.5, 0.333], [1.0, 0.0]], [[0.875, 0.167], [0.85, 0.2], [0.875, 0.2], [0.875, 0.167]]]]) self.assertEqual( self.polys_to_list(shape.toQPolygonF(QgsSymbol.Fill, QSizeF(10, 2))), [[[[10.0, 0.0], [0.0, 2.0], [5.0, 0.667], [10.0, 0.0]], [[8.75, 0.333], [8.5, 0.4], [8.75, 0.4], [8.75, 0.333]]]]) # circular shape = QgsLegendPatchShape( QgsSymbol.Fill, QgsGeometry.fromWkt( 'CurvePolygon(CircularString(5 5, 3 4, 1 2, 3 0, 5 5))'), False) self.assertEqual( self.polys_to_list(shape.toQPolygonF(QgsSymbol.Fill, QSizeF(1, 1)))[0][0][:5], [[0.746, -0.0], [0.722, 0.009], [0.698, 0.018], [0.675, 0.028], [0.651, 0.038]]) self.assertEqual( self.polys_to_list(shape.toQPolygonF(QgsSymbol.Fill, QSizeF(10, 2)))[0][0][:5], [[7.459, -0.0], [6.83, 0.04], [6.201, 0.09], [5.574, 0.151], [4.947, 0.223]]) # multipolygon shape = QgsLegendPatchShape( QgsSymbol.Fill, QgsGeometry.fromWkt( 'MultiPolygon(((5 5, 1 2, 3 4, 5 5), (4.5 4.5, 4.4 4.4, 4.5 4.4, 4.5 4.5)),((10 11, 11 11, 11 10, 10 11)))' ), False) self.assertEqual( self.polys_to_list(shape.toQPolygonF(QgsSymbol.Fill, QSizeF(1, 1))), [[[[0.4, 0.667], [0.0, 1.0], [0.2, 0.778], [0.4, 0.667]], [[0.35, 0.722], [0.34, 0.733], [0.35, 0.733], [0.35, 0.722]]], [[[0.9, 0.0], [1.0, 0.0], [1.0, 0.111], [0.9, 0.0]]]]) self.assertEqual( self.polys_to_list(shape.toQPolygonF(QgsSymbol.Fill, QSizeF(10, 2))), [[[[4.0, 1.333], [0.0, 2.0], [2.0, 1.556], [4.0, 1.333]], [[3.5, 1.444], [3.4, 1.467], [3.5, 1.467], [3.5, 1.444]]], [[[9.0, 0.0], [10.0, 0.0], [10.0, 0.222], [9.0, 0.0]]]])
def convert_fill_symbol_background( background_symbol, # pylint: disable=too-many-branches,too-many-statements context, reference_scale=None): """ Converts a fill symbol background to QgsTextBackgroundSettings """ settings = QgsTextBackgroundSettings() settings.setEnabled(True) settings.setType(QgsTextBackgroundSettings.ShapeRectangle) if isinstance(background_symbol, BalloonCallout): fill_symbol = background_symbol.fill_symbol if background_symbol.style == BalloonCallout.STYLE_ROUNDED_RECTANGLE: # TODO - confirm actual size rendering on Arc settings.setRadii(QSizeF(1, 1)) elif background_symbol.style == BalloonCallout.STYLE_OVAL: # TODO - verify comparitive rendering settings.setType(QgsTextBackgroundSettings.ShapeEllipse) else: fill_symbol = background_symbol.border_symbol from .symbols import SymbolConverter # pylint: disable=import-outside-toplevel # can't use the fill itself - we can only use the fill color and outline if isinstance(fill_symbol, SimpleFillSymbol): if not fill_symbol.color.is_null: fill_color = ColorConverter.color_to_qcolor(fill_symbol.color) settings.setFillColor(fill_color) else: settings.setFillColor(QColor()) if isinstance(fill_symbol.outline, SimpleLineSymbol): if not fill_symbol.outline.color.is_null: settings.setStrokeColor( ColorConverter.color_to_qcolor( fill_symbol.outline.color)) if reference_scale is None: settings.setStrokeWidth( context.convert_size(fill_symbol.outline.width)) settings.setStrokeWidthUnit(context.units) else: settings.setStrokeWidth(fill_symbol.outline.width * reference_scale * 0.000352778) settings.setStrokeWidthUnit( QgsUnitTypes.RenderMetersInMapUnits) else: stroke = SymbolConverter.Symbol_to_QgsSymbol( fill_symbol, context) if stroke: settings.setStrokeColor(stroke.color()) if reference_scale is None: settings.setStrokeWidth(0.2) settings.setStrokeWidthUnit( QgsUnitTypes.RenderMillimeters) else: settings.setStrokeWidth(0.2 * reference_scale * 0.001) settings.setStrokeWidthUnit( QgsUnitTypes.RenderMetersInMapUnits) else: symbol = SymbolConverter.Symbol_to_QgsSymbol(fill_symbol, context) settings.setFillColor(symbol.color()) settings.setSizeType(QgsTextBackgroundSettings.SizeBuffer) # TODO: margin x_margin = (background_symbol.margin_left + background_symbol.margin_right) / 2 y_margin = (background_symbol.margin_top + background_symbol.margin_bottom) / 2 x_delta = (background_symbol.margin_right - background_symbol.margin_left) / 2 y_delta = (background_symbol.margin_bottom - background_symbol.margin_top) / 2 if reference_scale is None: settings.setSize( QSizeF(context.convert_size(x_margin), context.convert_size(y_margin))) settings.setSizeUnit(context.units) else: settings.setSize( QSizeF(x_margin * reference_scale * 0.000352778, y_margin * reference_scale * 0.000352778)) settings.setSizeUnit(QgsUnitTypes.RenderMetersInMapUnits) if reference_scale is None: settings.setOffset( QPointF(context.convert_size(x_delta), context.convert_size(y_delta))) settings.setOffsetUnit(context.units) else: settings.setOffset( QPointF(x_delta * reference_scale * 0.000352778, y_delta * reference_scale * 0.000352778)) settings.setOffsetUnit(QgsUnitTypes.RenderMetersInMapUnits) return settings
def run(self): project_id = self.settings.value("project/id") epsg = self.settings.value("project/epsg") locale = QSettings().value('locale/userLocale')[0:2] if not project_id: self.message_bar.pushCritical( "Error", _translate("VeriSO_EE_Geb_LokTest", "project_id not set", None)) return QApplication.setOverrideCursor(Qt.WaitCursor) try: group = _translate("VeriSO_EE_Geb_LokTest", "Gebaeudeadressen - Lokalisationstest", None) group += " (" + str(project_id) + ")" # TODO: Check "tid" vs. t_ili_tid... in queries. Do not import # i_ili_tid? # define layer names here lokalisation = _translate("VeriSO_EE_Geb_LokTest", "Lokalisation Lokalisationstest", None) strassenstueck_geometrie = _translate( "VeriSO_EE_Geb_LokTest", "Strassenstueck (geometrie) " "Lokalisationstest", None) strassenstueck_anfangspunkt = _translate( "VeriSO_EE_Geb_LokTest", "Strassenstueck (" "anfangspunkt) " "Lokalisationstest", None) benanntesgebiet = _translate("VeriSO_EE_Geb_LokTest", "Benanntes Gebiet Lokalisationstest", None) gebaeudeeingang = _translate("VeriSO_EE_Geb_LokTest", "Gebaeudeeingang Lokalisationstest", None) shortestline = _translate("VeriSO_EE_Geb_LokTest", "Kuerzeste Linie Lokalisationstest", None) hausnummerpos = _translate("VeriSO_EE_Geb_LokTest", "HausnummerPos Lokalisationstest", None) lokalisationsname = _translate("VeriSO_EE_Geb_LokTest", "LokalisationsName", None) vlayer_lokalisation = self.get_vector_layer_by_name(lokalisation) if not vlayer_lokalisation: layer = { "type": "postgres", "title": lokalisation, "featuretype": "gebaeudeadressen_lokalisation", "key": "ogc_fid", "sql": "ogc_fid = -1", "readonly": True, "group": group } vlayer_lokalisation = self.layer_loader.load(layer) vlayer_strassenstueck_geometrie = self.get_vector_layer_by_name( strassenstueck_geometrie) if not vlayer_strassenstueck_geometrie: layer = { "type": "postgres", "title": "Strassenstueck (geometrie) Lokalisationstest", "featuretype": "gebaeudeadressen_strassenstueck", "geom": "geometrie", "key": "ogc_fid", "sql": "strassenstueck_von = -1", "readonly": True, "group": group, "style": "global_qml/gebaeudeadressen/strassenachsen_rot" ".qml" } vlayer_strassenstueck_geometrie = self.layer_loader.load(layer) vlayer_strassenstueck_anfangspunkt = self.get_vector_layer_by_name( strassenstueck_anfangspunkt) if not vlayer_strassenstueck_anfangspunkt: layer = { "type": "postgres", "title": "Strassenstueck (anfangspunkt) Lokalisationstest", "featuretype": "gebaeudeadressen_strassenstueck", "geom": "anfangspunkt", "key": "ogc_fid", "sql": "strassenstueck_von = -1", "readonly": True, "group": group, "style": "global_qml/gebaeudeadressen/anfangspunkt_rot.qml" } vlayer_strassenstueck_anfangspunkt = self.layer_loader.load( layer) vlayer_benanntesgebiet = self.get_vector_layer_by_name( benanntesgebiet) if not vlayer_benanntesgebiet: layer = { "type": "postgres", "title": "Benanntes Gebiet Lokalisationstest", "featuretype": "gebaeudeadressen_benanntesgebiet", "geom": "flaeche", "key": "ogc_fid", "sql": "benanntesgebiet_von = -1", "readonly": True, "group": group, "style": "global_qml/gebaeudeadressen/benanntesgebiet_rot" ".qml" } vlayer_benanntesgebiet = self.layer_loader.load(layer) vlayer_gebaeudeeingang = self.get_vector_layer_by_name( gebaeudeeingang) if not vlayer_gebaeudeeingang: layer = { "type": "postgres", "title": "Gebaeudeeingang Lokalisationstest", "featuretype": "gebaeudeadressen_gebaeudeeingang", "geom": "lage", "key": "ogc_fid", "sql": "gebaeudeeingang_von = -1", "readonly": True, "group": group, "style": "global_qml/gebaeudeadressen/gebaeudeeingang_rot" ".qml" } vlayer_gebaeudeeingang = self.layer_loader.load(layer) vlayer_shortestline = self.get_vector_layer_by_name(shortestline) if not vlayer_shortestline: layer = { "type": "postgres", "title": "Kuerzeste Linie Lokalisationstest", "featuretype": "t_shortestline_hausnummerpos", "geom": "the_geom", "key": "ogc_fid", "sql": "lok_tid = -1", "readonly": True, "group": group, "style": "global_qml/gebaeudeadressen/shortestline_linie_rot.qml" } vlayer_shortestline = self.layer_loader.load(layer) vlayer_hausnummerpos = self.get_vector_layer_by_name(hausnummerpos) if not vlayer_hausnummerpos: layer = { "type": "postgres", "title": "HausnummerPos Lokalisationstest", "featuretype": "v_gebaeudeadressen_hausnummerpos", "geom": "pos", "key": "ogc_fid", "sql": "lok_tid = -1", "readonly": True, "group": group, "style": "global_qml/gebaeudeadressen/hausnummerpos_rot.qml" } vlayer_hausnummerpos = self.layer_loader.load(layer) vlayer_lokalisationsname = self.get_vector_layer_by_name( lokalisationsname) if not vlayer_lokalisationsname: self.message_bar.pushMessage( "Error", _translate("VeriSO_EE_Geb_LokTest", "Layer _LokalisationsName_ not found.", None), level=QgsMessageBar.CRITICAL, duration=0) QApplication.restoreOverrideCursor() return iterator = vlayer_lokalisationsname.getFeatures() ids = [] for feature in iterator: ids.append(feature.id()) if vlayer_lokalisationsname.selectedFeatureCount() < 1: self.message_bar.pushCritical( "Error", _translate("VeriSO_EE_Geb_LokTest", "No _LokalisationsName_ selected.", None)) QApplication.restoreOverrideCursor() return if vlayer_lokalisationsname.selectedFeatureCount() > 1: self.message_bar.pushCritical( "Error", _translate( "VeriSO_EE_Geb_LokTest", "Please select only one (1) _LokalisationsName_.", None)) QApplication.restoreOverrideCursor() return feat = QgsFeature() id = vlayer_lokalisationsname.selectedFeaturesIds()[0] feat = vlayer_lokalisationsname.selectedFeatures()[0] idx = ids.index(id) benannte_idx = vlayer_lokalisationsname.fieldNameIndex("benannte") text_idx = vlayer_lokalisationsname.fieldNameIndex("atext") if benannte_idx == -1 or text_idx == -1: self.message_bar.pushCritical( "Error", _translate("VeriSO_EE_Geb_LokTest", "Field _benannte_ or _text_ not found.", None)) QApplication.restoreOverrideCursor() return benannte = feat.attributes()[benannte_idx] lokalisationsname = feat.attributes()[text_idx] vlayer_strassenstueck_geometrie.setSubsetString( "(strassenstueck_von = " + str(benannte) + ")") vlayer_strassenstueck_anfangspunkt.setSubsetString( "(strassenstueck_von = " + str(benannte) + ")") vlayer_benanntesgebiet.setSubsetString("(benanntesgebiet_von = " + str(benannte) + ")") vlayer_gebaeudeeingang.setSubsetString("(gebaeudeeingang_von = " + str(benannte) + ")") vlayer_lokalisation.setSubsetString("(ogc_fid = " + str(benannte) + ")") vlayer_shortestline.setSubsetString("(lok_tid = " + str(benannte) + ")") vlayer_hausnummerpos.setSubsetString("(lok_tid = " + str(benannte) + ")") if vlayer_strassenstueck_geometrie.featureCount() > 0: x_min = vlayer_strassenstueck_geometrie.extent().xMinimum() y_min = vlayer_strassenstueck_geometrie.extent().yMinimum() x_max = vlayer_strassenstueck_geometrie.extent().xMaximum() y_max = vlayer_strassenstueck_geometrie.extent().yMaximum() if vlayer_benanntesgebiet.featureCount() > 0: x_min = vlayer_benanntesgebiet.extent().xMinimum() y_min = vlayer_benanntesgebiet.extent().yMinimum() x_max = vlayer_benanntesgebiet.extent().xMaximum() y_max = vlayer_benanntesgebiet.extent().yMaximum() try: if vlayer_gebaeudeeingang.featureCount() > 0: if vlayer_gebaeudeeingang.extent().xMinimum() < x_min: x_min = vlayer_gebaeudeeingang.extent().xMinimum() if vlayer_gebaeudeeingang.extent().yMinimum() < y_min: y_min = vlayer_gebaeudeeingang.extent().yMinimum() if vlayer_gebaeudeeingang.extent().xMaximum() > x_max: x_max = vlayer_gebaeudeeingang.extent().xMaximum() if vlayer_gebaeudeeingang.extent().yMaximum() > y_max: y_max = vlayer_gebaeudeeingang.extent().yMaximum() rect = QgsRectangle(x_min, y_min, x_max, y_max) rect.scale(1.3) except UnboundLocalError: vlayer_gemeindegrenze = self.getVectorLayerByName( "Gemeindegrenze") if vlayer_gemeindegrenze is None: rect = self.canvas.fullExtent() else: rect = vlayer_gemeindegrenze.extent() self.iface.mapCanvas().setExtent(rect) self.iface.mapCanvas().refresh() iterator = vlayer_lokalisation.getFeatures() # only one feature is selected for feature in iterator: prinzip_idx = vlayer_lokalisation.fieldNameIndex( "nummerierungsprinzip_txt") attributeprovisorisch_idx = vlayer_lokalisation.fieldNameIndex( "attributeprovisorisch_txt") offiziell_idx = vlayer_lokalisation.fieldNameIndex( "istoffiziellebezeichnung_txt") status_idx = vlayer_lokalisation.fieldNameIndex("status_txt") inaenderung_idx = vlayer_lokalisation.fieldNameIndex( "inaenderung_txt") art_idx = vlayer_lokalisation.fieldNameIndex("art_txt") something_missing = (prinzip_idx == -1 or attributeprovisorisch_idx == -1 or offiziell_idx == -1 or status_idx == -1 or inaenderung_idx == -1 or art_idx == -1) if something_missing: self.message_bar.pushMessage("Error", _translate( "VeriSO_EE_Geb_LokTest", "Field not found.", None), level=QgsMessageBar.CRITICAL, duration=0) QApplication.restoreOverrideCursor() return prinzip = feature.attributes()[prinzip_idx] attributeprovisorisch = feature.attributes( )[attributeprovisorisch_idx] offiziell = feature.attributes()[offiziell_idx] status = feature.attributes()[status_idx] inaenderung = feature.attributes()[inaenderung_idx] art = feature.attributes()[art_idx] map_extent = self.canvas.extent() x = map_extent.xMinimum() y = map_extent.yMaximum() text_item_found = False items = list(self.iface.mapCanvas().scene().items()) for i in range(len(items)): try: name = items[i].data(0) if str(name) == "LokalisationsInfo": text_item = items[i] text_item_found = True except Exception: pass if not text_item_found: text_item = QgsTextAnnotationItem(self.canvas) text_item.setData(0, "LokalisationsInfo") # noinspection PyUnboundLocalVariable text_item.setMapPosition( QgsPoint(x + 10 * self.canvas.mapUnitsPerPixel(), y - 10 * self.canvas.mapUnitsPerPixel())) text_item.setMapPositionFixed(False) text_item.setFrameBorderWidth(0.0) text_item.setFrameColor(QColor(250, 250, 250, 255)) text_item.setFrameBackgroundColor(QColor(250, 250, 250, 123)) text_item.setFrameSize(QSizeF(250, 150)) text_document = QTextDocument() text_document.setHtml( "<table style='font-size:12px;'><tr><td>Lok.Name: </td><td>" + lokalisationsname + "</td></tr><tr><td>TID: </td><td>" + str(benannte) + "</td></tr> <tr><td>Num.prinzip: " "</td><td>" + str(prinzip) + "</td></tr> <tr><td>Attr. prov.: </td><td>" + str(attributeprovisorisch) + "</td></tr> <tr><td>ist " "offiziell: </td><td>" + str(offiziell) + "</td></tr> <tr><td>Status: " "</td><td>" + str(status) + "</td></tr> <tr><td>in Aenderung: " "</td><td>" + str(inaenderung) + "</td></tr> <tr><td>Art: " "</td><td>" + str(art) + "</td></tr> </table>") text_item.setDocument(text_document) # This is a workaround: first ever position is not correct. text_item.setMapPosition( QgsPoint(x + 10 * self.canvas.mapUnitsPerPixel(), y - 10 * self.canvas.mapUnitsPerPixel())) text_item.update() self.iface.mapCanvas().refresh() try: vlayer_lokalisationsname.setSelectedFeatures([ids[idx + 1]]) except IndexError: self.message_bar.pushInfo( "Information", _translate("VeriSO_EE_Geb_LokTest", "End of table.", None)) except Exception as e: QApplication.restoreOverrideCursor() exc_type, exc_value, exc_traceback = sys.exc_info() self.message_bar.pushMessage( "Error", str(traceback.format_exc(exc_traceback)), level=QgsMessageBar.CRITICAL, duration=0) QApplication.restoreOverrideCursor() QApplication.restoreOverrideCursor()
def canvasMoveEvent(self, mouseEvent): item = self.selectedItem() if not item: return annotation = item.annotation() if not annotation: return pixelToMmScale = 25.4 / self.canvas.logicalDpiX() if self.currentMoveAction == QgsMapCanvasAnnotationItem.MoveFramePosition: # move the entire frame newCanvasPos = item.pos() + (mouseEvent.pos() - self.lastMousePosition) if annotation.hasFixedMapPosition(): deltaX = pixelToMmScale * (mouseEvent.pos().x() - self.lastMousePosition.x()) deltaY = pixelToMmScale * (mouseEvent.pos().y() - self.lastMousePosition.y()) annotation.setFrameOffsetFromReferencePointMm( QPointF( annotation.frameOffsetFromReferencePointMm().x() + deltaX, annotation.frameOffsetFromReferencePointMm().y() + deltaY)) annotation.setRelativePosition( QPointF(newCanvasPos.x() / self.canvas.width(), newCanvasPos.y() / self.canvas.height())) item.update() QgsProject.instance().setDirty(True) elif self.currentMoveAction != QgsMapCanvasAnnotationItem.NoAction: # handle vertical frame resize actions only size = annotation.frameSizeMm() xmin = annotation.frameOffsetFromReferencePointMm().x() ymin = annotation.frameOffsetFromReferencePointMm().y() xmax = xmin + size.width() ymax = ymin + size.height() relPosX = annotation.relativePosition().x() relPosY = annotation.relativePosition().y() if (self.currentMoveAction == QgsMapCanvasAnnotationItem.ResizeFrameUp or self.currentMoveAction == QgsMapCanvasAnnotationItem.ResizeFrameLeftUp or self.currentMoveAction == QgsMapCanvasAnnotationItem.ResizeFrameRightUp): ymin += pixelToMmScale * (mouseEvent.pos().y() - self.lastMousePosition.y()) relPosY = (relPosY * self.canvas.height() + mouseEvent.pos().y() - self.lastMousePosition.y()) / self.canvas.height() if (self.currentMoveAction == QgsMapCanvasAnnotationItem.ResizeFrameDown or self.currentMoveAction == QgsMapCanvasAnnotationItem.ResizeFrameLeftDown or self.currentMoveAction == QgsMapCanvasAnnotationItem.ResizeFrameRightDown): ymax += pixelToMmScale * (mouseEvent.pos().y() - self.lastMousePosition.y()) if (self.currentMoveAction == QgsMapCanvasAnnotationItem.ResizeFrameLeft or self.currentMoveAction == QgsMapCanvasAnnotationItem.ResizeFrameLeftUp or self.currentMoveAction == QgsMapCanvasAnnotationItem.ResizeFrameLeftDown): xmin += pixelToMmScale * (mouseEvent.pos().x() - self.lastMousePosition.x()) relPosX = (relPosX * self.canvas.width() + mouseEvent.pos().x() - self.lastMousePosition.x()) / self.canvas.width() if (self.currentMoveAction == QgsMapCanvasAnnotationItem.ResizeFrameRight or self.currentMoveAction == QgsMapCanvasAnnotationItem.ResizeFrameRightUp or self.currentMoveAction == QgsMapCanvasAnnotationItem.ResizeFrameRightDown): xmax += pixelToMmScale * (mouseEvent.pos().x() - self.lastMousePosition.x()) # switch min / max if necessary if xmax < xmin: tmp = xmax xmax = xmin xmin = tmp if ymax < ymin: tmp = ymax ymax = ymin ymin = tmp annotation.setFrameOffsetFromReferencePointMm(QPointF(xmin, ymin)) annotation.setFrameSizeMm(QSizeF(xmax - xmin, ymax - ymin)) annotation.setRelativePosition(QPointF(relPosX, relPosY)) item.update() QgsProject.instance().setDirty(True) moveAction = item.moveActionForPosition(mouseEvent.pos()) cursor = QCursor() cursor.setShape(item.cursorShapeForAction(moveAction)) self.setCursor(cursor) self.lastMousePosition = mouseEvent.pos()
def convert_diagrams( renderer: AnnotateLayerPropertiesCollection, # pylint: disable=too-many-branches,too-many-statements dest_layer: QgsVectorLayer, context): """ Converts a diagram renderer to QGIS diagrams """ if not isinstance(renderer, ChartRenderer): return layer_settings = QgsDiagramLayerSettings() # todo - geometry type dependent layer_settings.placement = QgsDiagramLayerSettings.OverPoint if not renderer.prevent_overlap: layer_settings.setShowAllDiagrams(True) settings = QgsDiagramSettings() settings.categoryLabels = renderer.labels settings.categoryAttributes = renderer.attributes settings.categoryColors = [ SymbolConverter.symbol_to_color(c.symbol, context) for c in renderer.class_legend.classes ] if isinstance(renderer.symbol, BarChartSymbol): if renderer.symbol.display_in_3d and context.unsupported_object_callback: if context.layer_name: context.unsupported_object_callback( '{}: 3D bar chart was converted to 2d (QGIS does not support 3D bar charts)' .format(context.layer_name), level=Context.WARNING) elif context.symbol_name: context.unsupported_object_callback( '{}: 3D bar chart was converted to 2d (QGIS does not support 3D bar charts)' .format(context.symbol_name), level=Context.WARNING) else: context.unsupported_object_callback( '3D bar chart was converted to 2d (QGIS does not support 3D bar charts)', level=Context.WARNING) if renderer.class_legend.classes: first_symbol = renderer.class_legend.classes[0].symbol settings.penColor = SymbolConverter.symbol_to_line_color( first_symbol, context) settings.penWidth = SymbolConverter.symbol_to_line_width( first_symbol, context) settings.lineSizeUnit = context.units try: axis_symbol = SymbolConverter.Symbol_to_QgsSymbol( renderer.symbol.axis_symbol, context) settings.setShowAxis(renderer.symbol.show_axis) settings.setAxisLineSymbol(axis_symbol) except AttributeError: if context.unsupported_object_callback: if context.layer_name: context.unsupported_object_callback( '{}: Bar chart axis symbols require QGIS 3.12 or later' .format(context.layer_name), level=Context.WARNING) elif context.symbol_name: context.unsupported_object_callback( '{}: Bar chart axis symbols require QGIS 3.12 or later' .format(context.symbol_name), level=Context.WARNING) else: context.unsupported_object_callback( 'Bar chart axis symbols require QGIS 3.12 or later', level=Context.WARNING) settings.barWidth = renderer.symbol.bar_width * 0.352778 if renderer.symbol.spacing: try: settings.setSpacing( context.convert_size(renderer.symbol.spacing)) settings.setSpacingUnit(context.units) except AttributeError: if context.unsupported_object_callback: if context.layer_name: context.unsupported_object_callback( '{}: Bar chart spacing requires QGIS 3.12 or later' .format(context.layer_name), level=Context.WARNING) elif context.symbol_name: context.unsupported_object_callback( '{}: Bar chart spacing requires QGIS 3.12 or later' .format(context.symbol_name), level=Context.WARNING) else: context.unsupported_object_callback( 'Bar chart spacing requires QGIS 3.12 or later', level=Context.WARNING) if not renderer.symbol.orientation_vertical: settings.diagramOrientation = QgsDiagramSettings.Right diagram_renderer = QgsLinearlyInterpolatedDiagramRenderer() diagram_renderer.setDiagram(QgsHistogramDiagram()) diagram_renderer.setUpperValue(renderer.symbol.max_value) diagram_renderer.setUpperSize( QSizeF(renderer.symbol.max_length * 0.352778, renderer.symbol.max_length * 0.352778)) diagram_renderer.setDiagramSettings(settings) dest_layer.setDiagramRenderer(diagram_renderer) dest_layer.setDiagramLayerSettings(layer_settings) elif isinstance(renderer.symbol, PieChartSymbol): if renderer.symbol.display_in_3d and context.unsupported_object_callback: if context.layer_name: context.unsupported_object_callback( '{}: 3D pie chart was converted to 2d (QGIS does not support 3D pie charts)' .format(context.layer_name), level=Context.WARNING) elif context.symbol_name: context.unsupported_object_callback( '{}: 3D pie chart was converted to 2d (QGIS does not support 3D pie charts)' .format(context.symbol_name), level=Context.WARNING) else: context.unsupported_object_callback( '3D pie chart was converted to 2d (QGIS does not support 3D pie charts)', level=Context.WARNING) outline = SymbolConverter.Symbol_to_QgsSymbol( renderer.symbol.outline, context) settings.penWidth = outline.width() * 0.352778 settings.penColor = outline.color() # ArcMap only shows pie charts for features with some non-zero attributes exp = ' or '.join(settings.categoryAttributes) layer_settings.dataDefinedProperties().setProperty( QgsDiagramLayerSettings.Show, QgsProperty.fromExpression(exp)) if not renderer.vary_size_by_attribute: diagram_renderer = QgsSingleCategoryDiagramRenderer() else: diagram_renderer = QgsLinearlyInterpolatedDiagramRenderer() diagram_renderer.setClassificationField( renderer.vary_size_by_attribute) diagram_renderer.setLowerValue(renderer.min_value) diagram_renderer.setLowerSize( QSizeF(renderer.min_size * 0.352778 * 0.5, renderer.min_size * 0.352778 * 0.5)) diagram_renderer.setUpperValue(renderer.min_value * 2) diagram_renderer.setUpperSize( QSizeF(renderer.min_size * 0.352778 * 2 * 0.5, renderer.min_size * 0.352778 * 2 * 0.5)) settings.scaleByArea = False diagram_renderer.setDiagram(QgsPieDiagram()) settings.size = QSizeF(context.convert_size(renderer.symbol.size), context.convert_size(renderer.symbol.size)) settings.sizeType = context.units if renderer.symbol.clockwise: try: settings.setDirection(QgsDiagramSettings.Clockwise) except AttributeError: if context.unsupported_object_callback: if context.layer_name: context.unsupported_object_callback( '{}: Clockwise pie charts require QGIS 3.12 or later' .format(context.layer_name), level=Context.WARNING) elif context.symbol_name: context.unsupported_object_callback( '{}: Clockwise pie charts require QGIS 3.12 or later' .format(context.symbol_name), level=Context.WARNING) else: context.unsupported_object_callback( 'Clockwise pie charts require QGIS 3.12 or later', level=Context.WARNING) try: outline_symbol = SymbolConverter.Symbol_to_QgsSymbol( renderer.class_legend.classes[0].symbol.outline, context).color() if outline_symbol: settings.penColor = outline_symbol.color() settings.penWidth = outline_symbol.width() * 0.352778 except AttributeError: pass if not renderer.symbol.clockwise: settings.rotationOffset = renderer.symbol.starting_angle else: settings.rotationOffset = 360.0 - renderer.symbol.starting_angle diagram_renderer.setDiagramSettings(settings) dest_layer.setDiagramRenderer(diagram_renderer) dest_layer.setDiagramLayerSettings(layer_settings) else: raise NotImplementedException( 'Converting {} diagrams is not yet supported'.format( renderer.symbol.__class__.__name__))
def test_read_write(self): plot = Qgs2DPlot() plot.setSize(QSizeF(600, 500)) sym1 = QgsFillSymbol.createSimple({ 'color': '#fdbf6f', 'outline_style': 'no' }) plot.setChartBackgroundSymbol(sym1) sym2 = QgsFillSymbol.createSimple({ 'outline_color': '#0000ff', 'style': 'no', 'outline_style': 'solid', 'outline_width': 1 }) plot.setChartBorderSymbol(sym2) sym3 = QgsLineSymbol.createSimple({ 'outline_color': '#00ffff', 'outline_width': 1 }) plot.xAxis().setGridMajorSymbol(sym3) sym4 = QgsLineSymbol.createSimple({ 'outline_color': '#ff00ff', 'outline_width': 0.5 }) plot.xAxis().setGridMinorSymbol(sym4) sym3 = QgsLineSymbol.createSimple({ 'outline_color': '#0066ff', 'outline_width': 1 }) plot.yAxis().setGridMajorSymbol(sym3) sym4 = QgsLineSymbol.createSimple({ 'outline_color': '#ff4433', 'outline_width': 0.5 }) plot.yAxis().setGridMinorSymbol(sym4) font = QgsFontUtils.getStandardTestFont('Bold', 16) x_axis_format = QgsTextFormat.fromQFont(font) x_axis_format.setColor(QColor(255, 0, 0)) plot.xAxis().setTextFormat(x_axis_format) x_axis_number_format = QgsBasicNumericFormat() x_axis_number_format.setNumberDecimalPlaces(1) x_axis_number_format.setShowTrailingZeros(True) plot.xAxis().setNumericFormat(x_axis_number_format) font = QgsFontUtils.getStandardTestFont('Bold', 18) y_axis_format = QgsTextFormat.fromQFont(font) y_axis_format.setColor(QColor(0, 255, 0)) plot.yAxis().setTextFormat(y_axis_format) y_axis_number_format = QgsBasicNumericFormat() y_axis_number_format.setShowPlusSign(True) plot.yAxis().setNumericFormat(y_axis_number_format) plot.setXMinimum(3) plot.setXMaximum(9) plot.setYMinimum(2) plot.setYMaximum(12) plot.xAxis().setGridIntervalMinor(0.5) plot.xAxis().setGridIntervalMajor(1.5) plot.yAxis().setGridIntervalMinor(0.3) plot.yAxis().setGridIntervalMajor(1.3) plot.xAxis().setLabelInterval(32) plot.yAxis().setLabelInterval(23) doc = QDomDocument() elem = doc.createElement('test') plot.writeXml(elem, doc, QgsReadWriteContext()) res = Qgs2DPlot() self.assertTrue(res.readXml(elem, QgsReadWriteContext())) self.assertEqual(res.xMinimum(), 3) self.assertEqual(res.xMaximum(), 9) self.assertEqual(res.yMinimum(), 2) self.assertEqual(res.yMaximum(), 12) self.assertEqual(res.xAxis().gridIntervalMinor(), 0.5) self.assertEqual(res.xAxis().gridIntervalMajor(), 1.5) self.assertEqual(res.yAxis().gridIntervalMinor(), 0.3) self.assertEqual(res.yAxis().gridIntervalMajor(), 1.3) self.assertEqual(res.xAxis().labelInterval(), 32) self.assertEqual(res.yAxis().labelInterval(), 23) self.assertEqual(res.xAxis().numericFormat().numberDecimalPlaces(), 1) self.assertTrue(res.yAxis().numericFormat().showPlusSign()) self.assertEqual(res.xAxis().textFormat().color().name(), '#ff0000') self.assertEqual(res.yAxis().textFormat().color().name(), '#00ff00') self.assertEqual(res.chartBackgroundSymbol().color().name(), '#fdbf6f') self.assertEqual(res.chartBorderSymbol().color().name(), '#0000ff') self.assertEqual(res.xAxis().gridMinorSymbol().color().name(), '#ff00ff') self.assertEqual(res.xAxis().gridMajorSymbol().color().name(), '#00ffff') self.assertEqual(res.yAxis().gridMinorSymbol().color().name(), '#ff4433') self.assertEqual(res.yAxis().gridMajorSymbol().color().name(), '#0066ff')
def testDefault(self): self.assertEqual(QgsStyle.defaultStyle().defaultPatchAsQPolygonF(QgsSymbol.Hybrid, QSizeF(1, 1)), []) self.assertEqual(QgsStyle.defaultStyle().defaultPatchAsQPolygonF(QgsSymbol.Hybrid, QSizeF(10, 10)), []) # markers self.assertEqual(self.polys_to_list(QgsStyle.defaultStyle().defaultPatchAsQPolygonF(QgsSymbol.Marker, QSizeF(1, 1))), [[[[0.0, 0.0]]]]) self.assertEqual(self.polys_to_list(QgsStyle.defaultStyle().defaultPatchAsQPolygonF(QgsSymbol.Marker, QSizeF(2, 2))), [[[[1.0, 1.0]]]]) self.assertEqual(self.polys_to_list(QgsStyle.defaultStyle().defaultPatchAsQPolygonF(QgsSymbol.Marker, QSizeF(10, 2))), [[[[5.0, 1.0]]]]) # lines self.assertEqual(self.polys_to_list(QgsStyle.defaultStyle().defaultPatchAsQPolygonF(QgsSymbol.Line, QSizeF(1, 1))), [[[[0.0, 0.5], [1.0, 0.5]]]]) self.assertEqual(self.polys_to_list(QgsStyle.defaultStyle().defaultPatchAsQPolygonF(QgsSymbol.Line, QSizeF(10, 2))), [[[[0.0, 1.0], [10.0, 1.0]]]]) self.assertEqual(self.polys_to_list(QgsStyle.defaultStyle().defaultPatchAsQPolygonF(QgsSymbol.Line, QSizeF(9, 3))), [[[[0.0, 1.5], [9.0, 1.5]]]]) # fills self.assertEqual(self.polys_to_list(QgsStyle.defaultStyle().defaultPatchAsQPolygonF(QgsSymbol.Fill, QSizeF(1, 1))), [[[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0], [0.0, 0.0]]]]) self.assertEqual(self.polys_to_list(QgsStyle.defaultStyle().defaultPatchAsQPolygonF(QgsSymbol.Fill, QSizeF(10, 2))), [[[[0.0, 0.0], [10.0, 0.0], [10.0, 2.0], [0.0, 2.0], [0.0, 0.0]]]])
def __init__(self, size=QSizeF(400, 200), render_type=POINT_RENDERER, x_orientation=ORIENTATION_LEFT_TO_RIGHT, y_orientation=ORIENTATION_UPWARD, allow_mouse_translation=False, allow_wheel_zoom=False, symbology=None, parent=None): """ Parameters ---------- size: QSize Size of the item render_type: Literal[POINT_RENDERER, LINE_RENDERER, POLYGON_RENDERER] Type of renderer x_orientation: Literal[ORIENTATION_LEFT_TO_RIGHT, ORIENTATION_RIGHT_TO_LEFT] y_orientation: Literal[ORIENTATION_UPWARD, ORIENTATION_DOWNWARD] allow_mouse_translation: bool Allow the user to translate the item with the mouse (??) allow_wheel_zoom: bool Allow the user to zoom with the mouse wheel symbology: QDomDocument QGIS symbology to use for the renderer parent: QObject """ LogItem.__init__(self, parent) self.__item_size = size self.__data_rect = None self.__data = None self.__delta = None self.__x_orientation = x_orientation self.__y_orientation = y_orientation # origin point of the graph translation, if any self.__translation_orig = None self.__render_type = render_type # type: Literal[POINT_RENDERER, LINE_RENDERER, POLYGON_RENDERER] self.__allow_mouse_translation = allow_mouse_translation self.__allow_wheel_zoom = allow_wheel_zoom self.__layer = None self.__default_renderers = [QgsFeatureRenderer.defaultRenderer(POINT_RENDERER), QgsFeatureRenderer.defaultRenderer(LINE_RENDERER), QgsFeatureRenderer.defaultRenderer(POLYGON_RENDERER)] symbol = self.__default_renderers[1].symbol() symbol.setWidth(1.0) symbol = self.__default_renderers[0].symbol() symbol.setSize(5.0) symbol = self.__default_renderers[2].symbol() symbol.symbolLayers()[0].setStrokeWidth(1.0) if not symbology: self.__renderer = self.__default_renderers[self.__render_type] else: self.__renderer = QgsFeatureRenderer.load(symbology.documentElement(), QgsReadWriteContext()) # index of the current point to label self.__old_point_to_label = None self.__point_to_label = None
def testLines(self): shape = QgsLegendPatchShape( QgsSymbol.Line, QgsGeometry.fromWkt('LineString(5 5, 1 2)'), False) self.assertEqual( self.polys_to_list(shape.toQPolygonF(QgsSymbol.Line, QSizeF(1, 1))), [[[[1.0, 0.0], [0.0, 1.0]]]]) self.assertEqual( self.polys_to_list(shape.toQPolygonF(QgsSymbol.Line, QSizeF(10, 2))), [[[[10.0, 0.0], [0.0, 2.0]]]]) shape = QgsLegendPatchShape( QgsSymbol.Line, QgsGeometry.fromWkt('LineString(1 5, 6 5)'), False) self.assertEqual( self.polys_to_list(shape.toQPolygonF(QgsSymbol.Line, QSizeF(1, 1))), [[[[0.0, 0.5], [1.0, 0.5]]]]) self.assertEqual( self.polys_to_list(shape.toQPolygonF(QgsSymbol.Line, QSizeF(10, 2))), [[[[0.0, 1], [10.0, 1.0]]]]) shape = QgsLegendPatchShape( QgsSymbol.Line, QgsGeometry.fromWkt('LineString(1 5, 1 10)'), False) self.assertEqual( self.polys_to_list(shape.toQPolygonF(QgsSymbol.Line, QSizeF(1, 1))), [[[[0.5, 0.0], [0.5, 1.0]]]]) self.assertEqual( self.polys_to_list(shape.toQPolygonF(QgsSymbol.Line, QSizeF(10, 2))), [[[[5, 0.0], [5, 2.0]]]]) # requesting different symbol type, should return default self.assertEqual( self.polys_to_list(shape.toQPolygonF(QgsSymbol.Fill, QSizeF(1, 1))), [[[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0], [0.0, 0.0]]]]) # circularstring shape = QgsLegendPatchShape( QgsSymbol.Line, QgsGeometry.fromWkt('CircularString(5 5, 1 2, 3 4)'), False) self.assertEqual( self.polys_to_list(shape.toQPolygonF(QgsSymbol.Line, QSizeF(1, 1)))[0][0][:5], [[0.342, 0.026], [0.35, 0.023], [0.359, 0.02], [0.367, 0.018], [0.375, 0.016]]) self.assertEqual( self.polys_to_list(shape.toQPolygonF(QgsSymbol.Line, QSizeF(10, 2)))[0][0][:5], [[3.419, 0.051], [3.647, 0.042], [3.875, 0.036], [4.104, 0.034], [4.332, 0.036]]) # multilinestring shape = QgsLegendPatchShape( QgsSymbol.Line, QgsGeometry.fromWkt('MultiLineString((5 5, 1 2),(3 6, 4 2))'), False) self.assertEqual( self.polys_to_list(shape.toQPolygonF(QgsSymbol.Line, QSizeF(1, 1))), [[[[1.0, 0.25], [0.0, 1.0]]], [[[0.5, 0.0], [0.75, 1.0]]]]) self.assertEqual( self.polys_to_list(shape.toQPolygonF(QgsSymbol.Line, QSizeF(10, 2))), [[[[10.0, 0.5], [0.0, 2.0]]], [[[5.0, 0.0], [7.5, 2.0]]]])
def _get_layout_pdf_image(self, width, height, dpi): pdfpath = getTempfilePath('pdf') temp_size = os.path.getsize(pdfpath) p = QPrinter() p.setOutputFormat(QPrinter.PdfFormat) p.setOutputFileName(pdfpath) p.setPaperSize( QSizeF(self._c.pageCollection().page(0).sizeWithUnits().width(), self._c.pageCollection().page(0).sizeWithUnits().height()), QPrinter.Millimeter) p.setFullPage(True) p.setColorMode(QPrinter.Color) p.setResolution(self._c.renderContext().dpi()) pdf_p = QPainter(p) # page_mm = p.pageRect(QPrinter.Millimeter) # page_px = p.pageRect(QPrinter.DevicePixel) # self._c.render(pdf_p, page_px, page_mm) exporter = QgsLayoutExporter(self._c) exporter.renderPage(pdf_p, 0) pdf_p.end() if temp_size == os.path.getsize(pdfpath): return False, '' filepath = getTempfilePath('png') # Poppler (pdftocairo or pdftoppm): # PDFUTIL -png -singlefile -r 72 -x 0 -y 0 -W 420 -H 280 in.pdf pngbase # muPDF (mudraw): # PDFUTIL -c rgb[a] -r 72 -w 420 -h 280 -o out.png in.pdf if PDFUTIL.strip().endswith('pdftocairo'): filebase = os.path.join( os.path.dirname(filepath), os.path.splitext(os.path.basename(filepath))[0]) call = [ PDFUTIL, '-png', '-singlefile', '-r', str(dpi), '-x', '0', '-y', '0', '-W', str(width), '-H', str(height), pdfpath, filebase ] elif PDFUTIL.strip().endswith('mudraw'): call = [ PDFUTIL, '-c', 'rgba', '-r', str(dpi), '-w', str(width), '-h', str(height), # '-b', '8', '-o', filepath, pdfpath ] else: return False, '' qDebug("_get_layout_pdf_image call: {0}".format(' '.join(call))) res = False try: subprocess.check_call(call) res = True except subprocess.CalledProcessError as e: qDebug("_get_layout_pdf_image failed!\n" "cmd: {0}\n" "returncode: {1}\n" "message: {2}".format(e.cmd, e.returncode, e.message)) if not res: os.unlink(filepath) filepath = '' return res, filepath
def drawCostPaths(self, rows, con, args, geomType, canvasItemList, mapCanvas): resultPathsRubberBands = canvasItemList['paths'] rubberBand = None cur_path_id = -1 for row in rows: cur2 = con.cursor() args['result_path_id'] = row[0] args['result_source_id'] = sql.Literal(row[1]) args['result_target_id'] = sql.Literal(row[2]) args['result_cost'] = row[3] if args['result_path_id'] != cur_path_id: cur_path_id = args['result_path_id'] if rubberBand: resultPathsRubberBands.append(rubberBand) rubberBand = None rubberBand = QgsRubberBand(mapCanvas, Utils.getRubberBandType(False)) rubberBand.setColor(QColor(255, 0, 0, 128)) rubberBand.setWidth(4) if args['result_cost'] != -1: query2 = sql.SQL(""" SELECT ST_AsText( ST_MakeLine( (SELECT {geometry_vt} FROM {vertex_schema}.{vertex_table} WHERE id = {result_source_id}), (SELECT {geometry_vt} FROM {vertex_schema}.{vertex_table} WHERE id = {result_target_id}) )) """).format(**args) # Utils.logMessage(query2) cur2.execute(query2) row2 = cur2.fetchone() # Utils.logMessage(str(row2[0])) geom = QgsGeometry().fromWkt(str(row2[0])) if geom.wkbType() == QgsWkbTypes.MultiLineString: for line in geom.asMultiPolyline(): for pt in line: rubberBand.addPoint(pt) elif geom.wkbType() == QgsWkbTypes.LineString: for pt in geom.asPolyline(): rubberBand.addPoint(pt) # TODO label the edge instead of labeling the target points if rubberBand: resultPathsRubberBands.append(rubberBand) rubberBand = None resultNodesTextAnnotations = canvasItemList['annotations'] for row in rows: cur2 = con.cursor() args['result_seq'] = row[0] args['result_source_id'] = sql.Literal(row[1]) result_target_id = row[2] args['result_target_id'] = sql.Literal(result_target_id) result_cost = row[3] query2 = sql.SQL(""" SELECT ST_AsText( ST_startPoint({geometry}) ) FROM {edge_schema}.{edge_table} WHERE {source} = {result_target_id} UNION SELECT ST_AsText( ST_endPoint( {geometry} ) ) FROM {edge_schema}.{edge_table} WHERE {target} = {result_target_id} """).format(**args) cur2.execute(query2) row2 = cur2.fetchone() geom = QgsGeometry().fromWkt(str(row2[0])) pt = geom.asPoint() textDocument = QTextDocument("{0!s}:{1}".format(result_target_id, result_cost)) textAnnotation = QgsTextAnnotation() textAnnotation.setMapPosition(geom.asPoint()) textAnnotation.setFrameSize(QSizeF(textDocument.idealWidth(), 20)) textAnnotation.setFrameOffsetFromReferencePoint(QPointF(20, -40)) textAnnotation.setDocument(textDocument) QgsMapCanvasAnnotationItem(textAnnotation, mapCanvas) resultNodesTextAnnotations.append(textAnnotation)