def testOperators(self): rect1 = QgsRectangle(10, 20, 40, 40) rect2 = rect1 + QgsVector(3, 5.5) assert rect2 == QgsRectangle(13, 25.5, 43, 45.5), "QgsRectangle + operator does no work" # Subtracting the center point, so it becomes zero. rect1 -= rect1.center() - QgsPointXY(0, 0) assert rect1.center() == QgsPointXY(0, 0)
def testOperators(self): rect1 = QgsRectangle(10, 20, 40, 40) rect2 = rect1 + QgsVector(3, 5.5) self.assertEqual(rect2, QgsRectangle(13, 25.5, 43, 45.5)) # Subtracting the center point, so it becomes zero. rect1 -= rect1.center() - QgsPointXY(0, 0) self.assertEqual(rect1.center(), QgsPointXY(0, 0))
def processAlgorithm(self, progress): idx = self.getParameterValue(self.TYPE) extent = self.getParameterValue(self.EXTENT).split(',') hSpacing = self.getParameterValue(self.HSPACING) vSpacing = self.getParameterValue(self.VSPACING) crs = QgsCoordinateReferenceSystem(self.getParameterValue(self.CRS)) bbox = QgsRectangle(float(extent[0]), float(extent[2]), float(extent[1]), float(extent[3])) width = bbox.width() height = bbox.height() centerX = bbox.center().x() centerY = bbox.center().y() #~ originX = centerX - width / 2.0 #~ originY = centerY - height / 2.0 originX = bbox.xMinimum() originY = bbox.yMaximum() if hSpacing <= 0 or vSpacing <= 0: raise GeoAlgorithmExecutionException( self.tr('Invalid grid spacing: %s/%s' % (hSpacing, vSpacing))) if width < hSpacing: raise GeoAlgorithmExecutionException( self.tr('Horizontal spacing is too small for the covered area')) if height < vSpacing: raise GeoAlgorithmExecutionException( self.tr('Vertical spacing is too small for the covered area')) #if self.types[idx].find(self.tr('polygon')) >= 0: if idx != 0: geometryType = QGis.WKBPolygon else: geometryType = QGis.WKBLineString fields = [QgsField('left', QVariant.Double, '', 24, 16), QgsField('top', QVariant.Double, '', 24, 16), QgsField('right', QVariant.Double, '', 24, 16), QgsField('bottom', QVariant.Double, '', 24, 16) ] writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, geometryType, crs) if idx == 0: self._rectangleGridLine( writer, width, height, originX, originY, hSpacing, vSpacing) elif idx == 1: self._rectangleGridPoly( writer, width, height, originX, originY, hSpacing, vSpacing) elif idx == 2: self._diamondGrid( writer, width, height, originX, originY, hSpacing, vSpacing) elif idx == 3: self._hexagonGrid( writer, width, height, originX, originY, hSpacing, vSpacing) del writer
def update_extent(self, extent): """Update extent value in GUI based from an extent. :param extent: A list in the form [xmin, ymin, xmax, ymax] where all coordinates provided are in Geographic / EPSG:4326. :type extent: list """ self.x_minimum.setValue(extent[0]) self.y_minimum.setValue(extent[1]) self.x_maximum.setValue(extent[2]) self.y_maximum.setValue(extent[3]) # Updating the country if possible. rectangle = QgsRectangle(extent[0], extent[1], extent[2], extent[3]) center = rectangle.center() for country in self.bbox_countries: for polygon in self.bbox_countries[country]: if polygon.contains(center): index = self.country_comboBox.findText(country) self.country_comboBox.setCurrentIndex(index) break else: # Continue if the inner loop wasn't broken. continue # Inner loop was broken, break the outer. break else: self.country_comboBox.setCurrentIndex(0)
def processAlgorithm(self, progress): idx = self.getParameterValue(self.TYPE) extent = self.getParameterValue(self.EXTENT).split(',') hSpacing = self.getParameterValue(self.HSPACING) vSpacing = self.getParameterValue(self.VSPACING) bbox = QgsRectangle(float(extent[0]), float(extent[2]), float(extent[1]), float(extent[3])) width = bbox.width() height = bbox.height() centerX = bbox.center().x() centerY = bbox.center().y() originX = centerX - width / 2.0 originY = centerY - height / 2.0 crs = QgsCoordinateReferenceSystem(self.getParameterValue(self.CRS)) if hSpacing <= 0 or vSpacing <= 0: raise GeoAlgorithmExecutionException( self.tr('Invalid grid spacing: %s/%s' % (hSpacing, vSpacing))) if width < hSpacing: raise GeoAlgorithmExecutionException( self.tr( 'Horizontal spacing is too small for the covered area')) if height < vSpacing: raise GeoAlgorithmExecutionException( self.tr('Vertical spacing is too small for the covered area')) if self.TYPES[idx].find('polygon') >= 0: geometryType = QGis.WKBPolygon else: geometryType = QGis.WKBLineString fields = [ QgsField('left', QVariant.Double, '', 24, 16), QgsField('top', QVariant.Double, '', 24, 16), QgsField('right', QVariant.Double, '', 24, 16), QgsField('bottom', QVariant.Double, '', 24, 16) ] writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields, geometryType, crs) if idx == 0: self._rectangleGridLine(writer, width, height, originX, originY, hSpacing, vSpacing) elif idx == 1: self._rectangleGridPoly(writer, width, height, originX, originY, hSpacing, vSpacing) elif idx == 2: self._diamondGrid(writer, width, height, originX, originY, hSpacing, vSpacing) elif idx == 3: self._hexagonGrid(writer, width, height, originX, originY, hSpacing, vSpacing) del writer
def testDimensions(self): rect = QgsRectangle(0.0, 0.0, 10.0, 20.0) self.assertEqual(rect.width(), 10.0) self.assertEqual(rect.height(), 20.0) self.assertEqual(rect.center(), QgsPointXY(5.0, 10.0)) rect.scale(2.0) self.assertEqual(rect.width(), 20.0) self.assertEqual(rect.height(), 40.0)
def testDimensions(self): rect = QgsRectangle(0.0, 0.0, 10.0, 10.0) myMessage = "Expected: %s\nGot: %s\n" % (10.0, rect.width()) assert rect.width() == 10.0, myMessage myMessage = "Expected: %s\nGot: %s\n" % (10.0, rect.height()) assert rect.height() == 10.0, myMessage myMessage = "Expected: %s\nGot: %s\n" % ("5.0, 5.0", rect.center().toString()) assert rect.center() == QgsPoint(5.0, 5.0), myMessage rect.scale(2.0) myMessage = "Expected: %s\nGot: %s\n" % (20.0, rect.width()) assert rect.width() == 20.0, myMessage myMessage = "Expected: %s\nGot: %s\n" % (20.0, rect.height()) assert rect.height() == 20.0, myMessage
def testDimensions(self): rect = QgsRectangle(0.0, 0.0, 10.0, 10.0) myMessage = ('Expected: %s\nGot: %s\n' % (10.0, rect.width())) assert rect.width() == 10.0, myMessage myMessage = ('Expected: %s\nGot: %s\n' % (10.0, rect.height())) assert rect.height() == 10.0, myMessage myMessage = ('Expected: %s\nGot: %s\n' % ("5.0, 5.0", rect.center().toString())) assert rect.center() == QgsPointXY(5.0, 5.0), myMessage rect.scale(2.0) myMessage = ('Expected: %s\nGot: %s\n' % (20.0, rect.width())) assert rect.width() == 20.0, myMessage myMessage = ('Expected: %s\nGot: %s\n' % (20.0, rect.height())) assert rect.height() == 20.0, myMessage
def subrectangle(self, norm_rect, y_inverted=False): """ args: norm_rect -- QgsRectangle (0 <= xmin, 0 <= ymin, xmax <= 1, ymax <= 1) y_inverted -- If True, lower-left is (0, 1) and upper-right is (1, 0). Or else lower-left is (0, 0) and upper-right is (1, 1). """ ur_rect = self._unrotated_rect xmin = ur_rect.xMinimum() + norm_rect.xMinimum() * ur_rect.width() xmax = ur_rect.xMinimum() + norm_rect.xMaximum() * ur_rect.width() if y_inverted: ymin = ur_rect.yMaximum() - norm_rect.yMaximum() * ur_rect.height() ymax = ur_rect.yMaximum() - norm_rect.yMinimum() * ur_rect.height() else: ymin = ur_rect.yMinimum() + norm_rect.yMinimum() * ur_rect.height() ymax = ur_rect.yMinimum() + norm_rect.yMaximum() * ur_rect.height() rect = QgsRectangle(xmin, ymin, xmax, ymax) return RotatedRect(rect.center(), rect.width(), rect.height()).rotate(self._rotation, self._center)
def set_zoom(iface, extra_extent): """Sets the zoom level to include all layers (excluding tiles layer) with some extra extent Parameters ---------- iface: QGIS interface The QGIS iface module. extra_extent: float How much extra space around the layers eg. 1.1 is 10% extra """ zoom_extent = QgsRectangle() for layer in QgsProject.instance().mapLayers().values(): if 'xyz&url' not in layer.source(): zoom_extent.combineExtentWith(layer.extent()) if zoom_extent.center().x() != 0.0: wgsCRS = QgsCoordinateReferenceSystem(4326) QgsProject.instance().setCrs(wgsCRS) zoom_extent.scale(extra_extent) iface.mapCanvas().setExtent(zoom_extent) iface.mapCanvas().refresh() wgsCRS = QgsCoordinateReferenceSystem(3857) QgsProject.instance().setCrs(wgsCRS)
def import_params(self): setting_file = QFileDialog.getOpenFileName( self, self.tr("Open settings file"), self.lastSavingPath, "*.txt") if setting_file[0] != '': with open(setting_file[0]) as json_file: try: parameters = json.load(json_file) param_crs = QgsCoordinateReferenceSystem() param_crs.createFromProj4(parameters["crs_map"]) if (self.map_crs != param_crs): # do traslation transform = QgsCoordinateTransform( param_crs, self.map_crs, QgsProject.instance()) pointMin = transform.transform(parameters["roi_x_min"], parameters["roi_y_min"]) pointMax = transform.transform(parameters["roi_x_max"], parameters["roi_y_max"]) self.roi_x_max = pointMax.x() self.roi_y_min = pointMin.y() self.roi_x_min = pointMin.x() self.roi_y_max = pointMax.y() else: self.roi_x_max = parameters["roi_x_max"] self.roi_y_min = parameters["roi_y_min"] self.roi_x_min = parameters["roi_x_min"] self.roi_y_max = parameters["roi_y_max"] self.ui.XMaxLineEdit.setText(str(round(self.roi_x_max, 3))) self.ui.YMinLineEdit.setText(str(round(self.roi_y_min, 3))) self.ui.XMinLineEdit.setText(str(round(self.roi_x_min, 3))) self.ui.YMaxLineEdit.setText(str(round(self.roi_y_max, 3))) if "roi_rect_Param" in parameters: self.rect_Params = parameters["roi_rect_Param"] else: rec = QgsRectangle(self.roi_x_min, self.roi_y_min, self.roi_x_max, self.roi_y_max) self.rect_Params = { 'center': [rec.center().x(), rec.center().y()], 'width': rec.width(), 'height': rec.height(), 'rotation': 0 } self.ui.WidthGeoLineEdit.setText( str(round(self.rect_Params["width"], 3))) self.ui.HeightGeoLineEdit.setText( str(round(self.rect_Params["height"], 3))) self.ui.SpacingLineEdit.setText( str(round(parameters["spacing_mm"], 2))) self.scale = parameters['scale'] self.scale_h = parameters['scale_h'] self.scale_w = parameters['scale_w'] self.ui.ScaleLineEdit.setScale(int(parameters["scale"])) self.upload_size_from_scale() self.ui.ZScaleDoubleSpinBox.setValue(parameters["z_scale"]) self.get_z_max_z_min() self.ui.BaseHeightLineEdit.setText( str(round(parameters["z_base"], 3))) self.ui.RevereseZCheckBox.setChecked(parameters["z_inv"]) self.get_height_model() if "divideRow" in parameters: self.ui.RowPartsSpinBox.setValue( int(parameters["divideRow"])) if "divideCols" in parameters: self.ui.ColPartsSpinBox.setValue( int(parameters["divideCols"])) self.paint_extent(self.rect_Params) except: QMessageBox.warning(self, self.tr("Attention"), self.tr("Wrong file"))
def qgis_composer_renderer(impact_report, component): """Default Map Report Renderer using QGIS Composer. Render using qgis composer for a given impact_report data and component context. :param impact_report: ImpactReport contains data about the report that is going to be generated. :type impact_report: safe.report.impact_report.ImpactReport :param component: Contains the component metadata and context for rendering the output. :type component: safe.report.report_metadata.QgisComposerComponentsMetadata :return: Whatever type of output the component should be. .. versionadded:: 4.0 """ context = component.context qgis_composition_context = impact_report.qgis_composition_context # load composition object layout = QgsPrintLayout(QgsProject.instance()) # load template main_template_folder = impact_report.metadata.template_folder # we do this condition in case custom template was found if component.template.startswith('../qgis-composer-templates/'): template_path = os.path.join(main_template_folder, component.template) else: template_path = component.template with open(template_path) as template_file: template_content = template_file.read() document = QtXml.QDomDocument() # Replace for k, v in context.substitution_map.items(): template_content = template_content.replace('[{}]'.format(k), v) document.setContent(template_content) rwcontext = QgsReadWriteContext() load_status = layout.loadFromTemplate( document, rwcontext) if not load_status: raise TemplateLoadingError( tr('Error loading template: %s') % template_path) # replace image path for img in context.image_elements: item_id = img.get('id') path = img.get('path') image = layout_item(layout, item_id, QgsLayoutItemPicture) if image and path: image.setPicturePath(path) # replace html frame for html_el in context.html_frame_elements: item_id = html_el.get('id') mode = html_el.get('mode') html_element = layout_item(layout, item_id, QgsLayoutItemHtml) if html_element: if mode == 'text': text = html_el.get('text') text = text if text else '' html_element.setContentMode(QgsLayoutItemHtml.ManualHtml) html_element.setHtml(text) html_element.loadHtml() elif mode == 'url': url = html_el.get('url') html_element.setContentMode(QgsLayoutItemHtml.Url) qurl = QUrl.fromLocalFile(url) html_element.setUrl(qurl) original_crs = impact_report.impact_function.crs destination_crs = qgis_composition_context.map_settings.destinationCrs() coord_transform = QgsCoordinateTransform(original_crs, destination_crs, QgsProject.instance()) # resize map extent for map_el in context.map_elements: item_id = map_el.get('id') split_count = map_el.get('grid_split_count') layers = [ layer for layer in map_el.get('layers') if isinstance( layer, QgsMapLayer) ] map_extent_option = map_el.get('extent') composer_map = layout_item(layout, item_id, QgsLayoutItemMap) for index, layer in enumerate(layers): # we need to check whether the layer is registered or not registered_layer = ( QgsProject.instance().mapLayer(layer.id())) if registered_layer: if not registered_layer == layer: layers[index] = registered_layer else: QgsProject.instance().addMapLayer(layer) """:type: qgis.core.QgsLayoutItemMap""" if composer_map: # Search for specified map extent in the template. min_x = composer_map.extent().xMinimum() if ( impact_report.use_template_extent) else None min_y = composer_map.extent().yMinimum() if ( impact_report.use_template_extent) else None max_x = composer_map.extent().xMaximum() if ( impact_report.use_template_extent) else None max_y = composer_map.extent().yMaximum() if ( impact_report.use_template_extent) else None composer_map.setKeepLayerSet(True) layer_set = [l for l in layers if isinstance(l, QgsMapLayer)] composer_map.setLayers(layer_set) map_overview_extent = None if map_extent_option and isinstance( map_extent_option, QgsRectangle): # use provided map extent extent = coord_transform.transform(map_extent_option) for l in [layer for layer in layers if isinstance(layer, QgsMapLayer)]: layer_extent = coord_transform.transform(l.extent()) if l.name() == map_overview['id']: map_overview_extent = layer_extent else: # if map extent not provided, try to calculate extent # from list of given layers. Combine it so all layers were # shown properly extent = QgsRectangle() extent.setMinimal() for l in [layer for layer in layers if isinstance(layer, QgsMapLayer)]: # combine extent if different layer is provided. layer_extent = coord_transform.transform(l.extent()) extent.combineExtentWith(layer_extent) if l.name() == map_overview['id']: map_overview_extent = layer_extent width = extent.width() height = extent.height() longest_width = width if width > height else height half_length = longest_width / 2 margin = half_length / 5 center = extent.center() min_x = min_x or (center.x() - half_length - margin) max_x = max_x or (center.x() + half_length + margin) min_y = min_y or (center.y() - half_length - margin) max_y = max_y or (center.y() + half_length + margin) # noinspection PyCallingNonCallable square_extent = QgsRectangle(min_x, min_y, max_x, max_y) if component.key == 'population-infographic' and ( map_overview_extent): square_extent = map_overview_extent composer_map.zoomToExtent(square_extent) composer_map.invalidateCache() actual_extent = composer_map.extent() # calculate intervals for grid x_interval = actual_extent.width() / split_count composer_map.grid().setIntervalX(x_interval) y_interval = actual_extent.height() / split_count composer_map.grid().setIntervalY(y_interval) # calculate legend element for leg_el in context.map_legends: item_id = leg_el.get('id') title = leg_el.get('title') layers = [ layer for layer in leg_el.get('layers') if isinstance( layer, QgsMapLayer) ] symbol_count = leg_el.get('symbol_count') column_count = leg_el.get('column_count') legend = layout_item(layout, item_id, QgsLayoutItemLegend) """:type: qgis.core.QgsLayoutItemLegend""" if legend: # set column count if column_count: legend.setColumnCount(column_count) elif symbol_count <= 7: legend.setColumnCount(1) else: legend.setColumnCount(symbol_count / 7 + 1) # set legend title if title is not None and not impact_report.legend_layers: legend.setTitle(title) # set legend root_group = legend.model().rootGroup() for layer in layers: # we need to check whether the layer is registered or not registered_layer = ( QgsProject.instance().mapLayer(layer.id())) if registered_layer: if not registered_layer == layer: layer = registered_layer else: QgsProject.instance().addMapLayer(layer) # used for customizations tree_layer = root_group.addLayer(layer) if impact_report.legend_layers or ( not impact_report.multi_exposure_impact_function): QgsLegendRenderer.setNodeLegendStyle( tree_layer, QgsLegendStyle.Hidden) legend.adjustBoxSize() legend.updateFilterByMap(False) # process to output # in case output folder not specified if impact_report.output_folder is None: impact_report.output_folder = mkdtemp(dir=temp_dir()) output_format = component.output_format component_output_path = impact_report.component_absolute_output_path( component.key) component_output = None doc_format = QgisComposerComponentsMetadata.OutputFormat.DOC_OUTPUT template_format = QgisComposerComponentsMetadata.OutputFormat.QPT if isinstance(output_format, list): component_output = [] for i in range(len(output_format)): each_format = output_format[i] each_path = component_output_path[i] if each_format in doc_format: result_path = create_qgis_pdf_output( impact_report, each_path, layout, each_format, component) component_output.append(result_path) elif each_format == template_format: result_path = create_qgis_template_output( each_path, layout) component_output.append(result_path) elif isinstance(output_format, dict): component_output = {} for key, each_format in list(output_format.items()): each_path = component_output_path[key] if each_format in doc_format: result_path = create_qgis_pdf_output( impact_report, each_path, layout, each_format, component) component_output[key] = result_path elif each_format == template_format: result_path = create_qgis_template_output( each_path, layout) component_output[key] = result_path elif (output_format in QgisComposerComponentsMetadata.OutputFormat.SUPPORTED_OUTPUT): component_output = None if output_format in doc_format: result_path = create_qgis_pdf_output( impact_report, component_output_path, layout, output_format, component) component_output = result_path elif output_format == template_format: result_path = create_qgis_template_output( component_output_path, layout) component_output = result_path component.output = component_output return component.output
def qgis_composer_renderer(impact_report, component): """Default Map Report Renderer using QGIS Composer. Render using qgis composer for a given impact_report data and component context :param impact_report: ImpactReport contains data about the report that is going to be generated :type impact_report: safe.report.impact_report.ImpactReport :param component: Contains the component metadata and context for rendering the output :type component: safe.report.report_metadata.QgisComposerComponentsMetadata :return: whatever type of output the component should be .. versionadded:: 4.0 """ context = component.context """:type: safe.report.extractors.composer.QGISComposerContext""" qgis_composition_context = impact_report.qgis_composition_context inasafe_context = impact_report.inasafe_context # load composition object composition = QgsComposition(qgis_composition_context.map_settings) # load template main_template_folder = impact_report.metadata.template_folder template_path = os.path.join(main_template_folder, component.template) with open(template_path) as template_file: template_content = template_file.read() document = QtXml.QDomDocument() document.setContent(template_content) load_status = composition.loadFromTemplate( document, context.substitution_map) if not load_status: raise TemplateLoadingError( tr('Error loading template: %s') % template_path) # replace image path for img in context.image_elements: item_id = img.get('id') path = img.get('path') image = composition.getComposerItemById(item_id) """:type: qgis.core.QgsComposerPicture""" if image is not None and path is not None: try: image.setPicturePath(path) except: pass # replace html frame for html_el in context.html_frame_elements: item_id = html_el.get('id') mode = html_el.get('mode') html_element = composition.getComposerItemById(item_id) """:type: qgis.core.QgsComposerHtml""" if html_element: if mode == 'text': text = html_el.get('text') text = text if text else '' html_element.setContentMode(QgsComposerHtml.ManualHtml) html_element.setHtml(text) html_element.loadHtml() elif mode == 'url': url = html_el.get('url') html_element.setContentMode(QgsComposerHtml.Url) qurl = QUrl.fromLocalFile(url) html_element.setUrl(qurl) # resize map extent for map_el in context.map_elements: item_id = map_el.get('id') split_count = map_el.get('grid_split_count') layers = map_el.get('layers') map_extent_option = map_el.get('extent') composer_map = composition.getComposerItemById(item_id) """:type: qgis.core.QgsComposerMap""" if isinstance(composer_map, QgsComposerMap): composer_map.setKeepLayerSet(True) layer_set = [l.id() for l in layers if isinstance(l, QgsMapLayer)] composer_map.setLayerSet(layer_set) if map_extent_option and isinstance( map_extent_option, QgsRectangle): # use provided map extent extent = map_extent_option else: # if map extent not provided, try to calculate extent # from list of given layers. Combine it so all layers were # shown properly extent = QgsRectangle() extent.setMinimal() for l in layers: # combine extent if different layer is provided. extent.combineExtentWith(l.extent()) width = extent.width() height = extent.height() longest_width = width if width > height else height half_length = longest_width / 2 margin = half_length / 5 center = extent.center() min_x = center.x() - half_length - margin max_x = center.x() + half_length + margin min_y = center.y() - half_length - margin max_y = center.y() + half_length + margin # noinspection PyCallingNonCallable square_extent = QgsRectangle(min_x, min_y, max_x, max_y) composer_map.zoomToExtent(square_extent) composer_map.renderModeUpdateCachedImage() actual_extent = composer_map.extent() # calculate intervals for grid x_interval = actual_extent.width() / split_count composer_map.grid().setIntervalX(x_interval) y_interval = actual_extent.height() / split_count composer_map.grid().setIntervalY(y_interval) # calculate legend element for leg_el in context.map_legends: item_id = leg_el.get('id') title = leg_el.get('title') layers = leg_el.get('layers') symbol_count = leg_el.get('symbol_count') column_count = leg_el.get('column_count') legend = composition.getComposerItemById(item_id) """:type: qgis.core.QgsComposerLegend""" if isinstance(legend, QgsComposerLegend): # set column count if column_count: legend.setColumnCount(column_count) elif symbol_count <= 5: legend.setColumnCount(1) else: legend.setColumnCount(symbol_count / 5 + 1) # set legend title if title is not None: legend.setTitle(title) # set legend root_group = legend.modelV2().rootGroup() for l in layers: # used for customizations tree_layer = root_group.addLayer(l) QgsLegendRenderer.setNodeLegendStyle( tree_layer, QgsComposerLegendStyle.Hidden) legend.synchronizeWithModel() # process to output # in case output folder not specified if impact_report.output_folder is None: impact_report.output_folder = mkdtemp(dir=temp_dir()) output_format = component.output_format component_output_path = impact_report.component_absolute_output_path( component.key) component_output = None doc_format = QgisComposerComponentsMetadata.OutputFormat.DOC_OUTPUT template_format = QgisComposerComponentsMetadata.OutputFormat.QPT if isinstance(output_format, list): component_output = [] for i in range(len(output_format)): each_format = output_format[i] each_path = component_output_path[i] if each_format in doc_format: result_path = create_qgis_pdf_output( each_path, composition, impact_report.qgis_composition_context, each_format, component) component_output.append(result_path) elif each_format == template_format: result_path = create_qgis_template_output( each_path, composition) component_output.append(result_path) elif isinstance(output_format, dict): component_output = {} for key, each_format in output_format.iteritems(): each_path = component_output_path[key] if each_format in doc_format: result_path = create_qgis_pdf_output( each_path, composition, impact_report.qgis_composition_context, each_format, component) component_output[key] = result_path elif each_format == template_format: result_path = create_qgis_template_output( each_path, composition) component_output[key] = result_path elif (output_format in QgisComposerComponentsMetadata.OutputFormat.SUPPORTED_OUTPUT): component_output = None if output_format in doc_format: result_path = create_qgis_pdf_output( component_output_path, composition, impact_report.qgis_composition_context, output_format, component) component_output = result_path elif output_format == template_format: result_path = create_qgis_template_output( component_output_path, composition) component_output = result_path component.output = component_output return component.output
def qgis_composer_renderer(impact_report, component): """Default Map Report Renderer using QGIS Composer. Render using qgis composer for a given impact_report data and component context. :param impact_report: ImpactReport contains data about the report that is going to be generated. :type impact_report: safe.report.impact_report.ImpactReport :param component: Contains the component metadata and context for rendering the output. :type component: safe.report.report_metadata.QgisComposerComponentsMetadata :return: Whatever type of output the component should be. .. versionadded:: 4.0 """ context = component.context """:type: safe.report.extractors.composer.QGISComposerContext""" qgis_composition_context = impact_report.qgis_composition_context # load composition object composition = QgsComposition(qgis_composition_context.map_settings) # load template main_template_folder = impact_report.metadata.template_folder # we do this condition in case custom template was found if component.template.startswith('../qgis-composer-templates/'): template_path = os.path.join(main_template_folder, component.template) else: template_path = component.template with open(template_path) as template_file: template_content = template_file.read() document = QtXml.QDomDocument() document.setContent(template_content) load_status = composition.loadFromTemplate( document, context.substitution_map) if not load_status: raise TemplateLoadingError( tr('Error loading template: %s') % template_path) # replace image path for img in context.image_elements: item_id = img.get('id') path = img.get('path') image = composition_item(composition, item_id, QgsComposerPicture) """:type: qgis.core.QgsComposerPicture""" if image and path: image.setPicturePath(path) # replace html frame for html_el in context.html_frame_elements: item_id = html_el.get('id') mode = html_el.get('mode') composer_item = composition.getComposerItemById(item_id) try: html_element = composition.getComposerHtmlByItem(composer_item) except: pass """:type: qgis.core.QgsComposerHtml""" if html_element: if mode == 'text': text = html_el.get('text') text = text if text else '' html_element.setContentMode(QgsComposerHtml.ManualHtml) html_element.setHtml(text) html_element.loadHtml() elif mode == 'url': url = html_el.get('url') html_element.setContentMode(QgsComposerHtml.Url) qurl = QUrl.fromLocalFile(url) html_element.setUrl(qurl) original_crs = impact_report.impact_function.crs destination_crs = qgis_composition_context.map_settings.destinationCrs() coord_transform = QgsCoordinateTransform(original_crs, destination_crs) # resize map extent for map_el in context.map_elements: item_id = map_el.get('id') split_count = map_el.get('grid_split_count') layers = [ layer for layer in map_el.get('layers') if isinstance( layer, QgsMapLayer) ] map_extent_option = map_el.get('extent') composer_map = composition_item(composition, item_id, QgsComposerMap) for index, layer in enumerate(layers): # we need to check whether the layer is registered or not registered_layer = ( QgsMapLayerRegistry.instance().mapLayer(layer.id())) if registered_layer: if not registered_layer == layer: layers[index] = registered_layer else: QgsMapLayerRegistry.instance().addMapLayer(layer) """:type: qgis.core.QgsComposerMap""" if composer_map: # Search for specified map extent in the template. min_x = composer_map.extent().xMinimum() if ( impact_report.use_template_extent) else None min_y = composer_map.extent().yMinimum() if ( impact_report.use_template_extent) else None max_x = composer_map.extent().xMaximum() if ( impact_report.use_template_extent) else None max_y = composer_map.extent().yMaximum() if ( impact_report.use_template_extent) else None composer_map.setKeepLayerSet(True) layer_set = [l.id() for l in layers if isinstance(l, QgsMapLayer)] composer_map.setLayerSet(layer_set) map_overview_extent = None if map_extent_option and isinstance( map_extent_option, QgsRectangle): # use provided map extent extent = coord_transform.transform(map_extent_option) for l in [layer for layer in layers if isinstance(layer, QgsMapLayer)]: layer_extent = coord_transform.transform(l.extent()) if l.name() == map_overview['id']: map_overview_extent = layer_extent else: # if map extent not provided, try to calculate extent # from list of given layers. Combine it so all layers were # shown properly extent = QgsRectangle() extent.setMinimal() for l in [layer for layer in layers if isinstance(layer, QgsMapLayer)]: # combine extent if different layer is provided. layer_extent = coord_transform.transform(l.extent()) extent.combineExtentWith(layer_extent) if l.name() == map_overview['id']: map_overview_extent = layer_extent width = extent.width() height = extent.height() longest_width = width if width > height else height half_length = longest_width / 2 margin = half_length / 5 center = extent.center() min_x = min_x or (center.x() - half_length - margin) max_x = max_x or (center.x() + half_length + margin) min_y = min_y or (center.y() - half_length - margin) max_y = max_y or (center.y() + half_length + margin) # noinspection PyCallingNonCallable square_extent = QgsRectangle(min_x, min_y, max_x, max_y) if component.key == 'population-infographic' and ( map_overview_extent): square_extent = map_overview_extent composer_map.zoomToExtent(square_extent) composer_map.renderModeUpdateCachedImage() actual_extent = composer_map.extent() # calculate intervals for grid x_interval = actual_extent.width() / split_count composer_map.grid().setIntervalX(x_interval) y_interval = actual_extent.height() / split_count composer_map.grid().setIntervalY(y_interval) # calculate legend element for leg_el in context.map_legends: item_id = leg_el.get('id') title = leg_el.get('title') layers = [ layer for layer in leg_el.get('layers') if isinstance( layer, QgsMapLayer) ] symbol_count = leg_el.get('symbol_count') column_count = leg_el.get('column_count') legend = composition_item(composition, item_id, QgsComposerLegend) """:type: qgis.core.QgsComposerLegend""" if legend: # set column count if column_count: legend.setColumnCount(column_count) elif symbol_count <= 7: legend.setColumnCount(1) else: legend.setColumnCount(symbol_count / 7 + 1) # set legend title if title is not None and not impact_report.legend_layers: legend.setTitle(title) # set legend root_group = legend.modelV2().rootGroup() for layer in layers: # we need to check whether the layer is registered or not registered_layer = ( QgsMapLayerRegistry.instance().mapLayer(layer.id())) if registered_layer: if not registered_layer == layer: layer = registered_layer else: QgsMapLayerRegistry.instance().addMapLayer(layer) # used for customizations tree_layer = root_group.addLayer(layer) if impact_report.legend_layers or ( not impact_report.multi_exposure_impact_function): QgsLegendRenderer.setNodeLegendStyle( tree_layer, QgsComposerLegendStyle.Hidden) legend.synchronizeWithModel() # process to output # in case output folder not specified if impact_report.output_folder is None: impact_report.output_folder = mkdtemp(dir=temp_dir()) output_format = component.output_format component_output_path = impact_report.component_absolute_output_path( component.key) component_output = None doc_format = QgisComposerComponentsMetadata.OutputFormat.DOC_OUTPUT template_format = QgisComposerComponentsMetadata.OutputFormat.QPT if isinstance(output_format, list): component_output = [] for i in range(len(output_format)): each_format = output_format[i] each_path = component_output_path[i] if each_format in doc_format: result_path = create_qgis_pdf_output( impact_report, each_path, composition, each_format, component) component_output.append(result_path) elif each_format == template_format: result_path = create_qgis_template_output( each_path, composition) component_output.append(result_path) elif isinstance(output_format, dict): component_output = {} for key, each_format in output_format.iteritems(): each_path = component_output_path[key] if each_format in doc_format: result_path = create_qgis_pdf_output( impact_report, each_path, composition, each_format, component) component_output[key] = result_path elif each_format == template_format: result_path = create_qgis_template_output( each_path, composition) component_output[key] = result_path elif (output_format in QgisComposerComponentsMetadata.OutputFormat.SUPPORTED_OUTPUT): component_output = None if output_format in doc_format: result_path = create_qgis_pdf_output( impact_report, component_output_path, composition, output_format, component) component_output = result_path elif output_format == template_format: result_path = create_qgis_template_output( component_output_path, composition) component_output = result_path component.output = component_output return component.output
def drawDebugInformation(layer, renderContext, zoom, xmin, ymin, xmax, ymax): self = layer mapSettings = self.iface.mapCanvas().mapSettings() lines = [] lines.append("TileLayer") lines.append(" zoom: %d, tile matrix extent: (%d, %d) - (%d, %d), tile count: %d * %d" % (zoom, xmin, ymin, xmax, ymax, xmax - xmin, ymax - ymin)) extent = renderContext.extent() lines.append(" map extent (renderContext): %s" % extent.toString()) lines.append(" map center (renderContext): %lf, %lf" % (extent.center().x(), extent.center().y())) lines.append(" map size: %f, %f" % (extent.width(), extent.height())) lines.append(" map extent (map canvas): %s" % self.iface.mapCanvas().extent().toString()) map2pixel = renderContext.mapToPixel() painter = renderContext.painter() viewport = painter.viewport() mapExtent = QgsRectangle(map2pixel.toMapCoordinatesF(0, 0), map2pixel.toMapCoordinatesF(viewport.width(), viewport.height())) lines.append(" map extent (calculated): %s" % mapExtent.toString()) lines.append(" map center (calc rect): %lf, %lf" % (mapExtent.center().x(), mapExtent.center().y())) center = map2pixel.toMapCoordinatesF(0.5 * viewport.width(), 0.5 * viewport.height()) lines.append(" map center (calc pt): %lf, %lf" % (center.x(), center.y())) lines.append(" viewport size (pixel): %d, %d" % (viewport.width(), viewport.height())) lines.append(" window size (pixel): %d, %d" % (painter.window().width(), painter.window().height())) lines.append(" outputSize (pixel): %d, %d" % (mapSettings.outputSize().width(), mapSettings.outputSize().height())) device = painter.device() lines.append(" deviceSize (pixel): %f, %f" % (device.width(), device.height())) lines.append(" logicalDpi: %f, %f" % (device.logicalDpiX(), device.logicalDpiY())) lines.append(" outputDpi: %f" % mapSettings.outputDpi()) lines.append(" mapToPixel: %s" % map2pixel.showParameters()) mupp = map2pixel.mapUnitsPerPixel() lines.append(" map units per pixel: %f" % mupp) lines.append(" meters per pixel (renderContext): %f" % (extent.width() / viewport.width())) transform = renderContext.coordinateTransform() if transform: mpp = mupp * {QGis.Feet: 0.3048, QGis.Degrees: self.layerDef.TSIZE1 / 180}.get(transform.destCRS().mapUnits(), 1) lines.append(" meters per pixel (calc 1): %f" % mpp) cx, cy = 0.5 * viewport.width(), 0.5 * viewport.height() geometry = QgsGeometry.fromPolyline([map2pixel.toMapCoordinatesF(cx - 0.5, cy), map2pixel.toMapCoordinatesF(cx + 0.5, cy)]) geometry.transform(QgsCoordinateTransform(transform.destCRS(), transform.sourceCrs())) # project CRS to layer CRS (EPSG:3857) mpp = geometry.length() lines.append(" meters per pixel (calc center pixel): %f" % mpp) lines.append(" scaleFactor: %f" % renderContext.scaleFactor()) lines.append(" rendererScale: %f" % renderContext.rendererScale()) scaleX, scaleY = self.getScaleToVisibleExtent(renderContext) lines.append(" scale: %f, %f" % (scaleX, scaleY)) # draw information textRect = painter.boundingRect(QRect(QPoint(0, 0), viewport.size()), Qt.AlignLeft, "Q") for i, line in enumerate(lines): painter.drawText(10, (i + 1) * textRect.height(), line) self.log(line) # diagonal painter.drawLine(QPointF(0, 0), QPointF(painter.viewport().width(), painter.viewport().height())) painter.drawLine(QPointF(painter.viewport().width(), 0), QPointF(0, painter.viewport().height())) # credit label margin, paddingH, paddingV = (3, 4, 3) credit = "This is credit" rect = QRect(0, 0, painter.viewport().width() - margin, painter.viewport().height() - margin) textRect = painter.boundingRect(rect, Qt.AlignBottom | Qt.AlignRight, credit) bgRect = QRect(textRect.left() - paddingH, textRect.top() - paddingV, textRect.width() + 2 * paddingH, textRect.height() + 2 * paddingV) painter.drawRect(bgRect) painter.drawText(rect, Qt.AlignBottom | Qt.AlignRight, credit)
def drawDebugInformation(layer, renderContext, zoom, xmin, ymin, xmax, ymax): self = layer mapSettings = self.iface.mapCanvas().mapSettings() lines = [] lines.append("TileLayer") lines.append( " zoom: %d, tile matrix extent: (%d, %d) - (%d, %d), tile count: %d * %d" % (zoom, xmin, ymin, xmax, ymax, xmax - xmin, ymax - ymin)) extent = renderContext.extent() lines.append(" map extent (renderContext): %s" % extent.toString()) lines.append(" map center (renderContext): %lf, %lf" % (extent.center().x(), extent.center().y())) lines.append(" map size: %f, %f" % (extent.width(), extent.height())) lines.append(" map extent (map canvas): %s" % self.iface.mapCanvas().extent().toString()) map2pixel = renderContext.mapToPixel() painter = renderContext.painter() viewport = painter.viewport() mapExtent = QgsRectangle( map2pixel.toMapCoordinatesF(0, 0), map2pixel.toMapCoordinatesF(viewport.width(), viewport.height())) lines.append(" map extent (calculated): %s" % mapExtent.toString()) lines.append(" map center (calc rect): %lf, %lf" % (mapExtent.center().x(), mapExtent.center().y())) center = map2pixel.toMapCoordinatesF(0.5 * viewport.width(), 0.5 * viewport.height()) lines.append(" map center (calc pt): %lf, %lf" % (center.x(), center.y())) lines.append(" viewport size (pixel): %d, %d" % (viewport.width(), viewport.height())) lines.append(" window size (pixel): %d, %d" % (painter.window().width(), painter.window().height())) lines.append( " outputSize (pixel): %d, %d" % (mapSettings.outputSize().width(), mapSettings.outputSize().height())) device = painter.device() lines.append(" deviceSize (pixel): %f, %f" % (device.width(), device.height())) lines.append(" logicalDpi: %f, %f" % (device.logicalDpiX(), device.logicalDpiY())) lines.append(" outputDpi: %f" % mapSettings.outputDpi()) lines.append(" mapToPixel: %s" % map2pixel.showParameters()) mupp = map2pixel.mapUnitsPerPixel() lines.append(" map units per pixel: %f" % mupp) lines.append(" meters per pixel (renderContext): %f" % (extent.width() / viewport.width())) transform = renderContext.coordinateTransform() if transform: mpp = mupp * { QGis.Feet: 0.3048, QGis.Degrees: self.layerDef.TSIZE1 / 180 }.get(transform.destCRS().mapUnits(), 1) lines.append(" meters per pixel (calc 1): %f" % mpp) cx, cy = 0.5 * viewport.width(), 0.5 * viewport.height() geometry = QgsGeometry.fromPolyline([ map2pixel.toMapCoordinatesF(cx - 0.5, cy), map2pixel.toMapCoordinatesF(cx + 0.5, cy) ]) geometry.transform( QgsCoordinateTransform( transform.destCRS(), transform.sourceCrs())) # project CRS to layer CRS (EPSG:3857) mpp = geometry.length() lines.append(" meters per pixel (calc center pixel): %f" % mpp) lines.append(" scaleFactor: %f" % renderContext.scaleFactor()) lines.append(" rendererScale: %f" % renderContext.rendererScale()) scaleX, scaleY = self.getScaleToVisibleExtent(renderContext) lines.append(" scale: %f, %f" % (scaleX, scaleY)) # draw information textRect = painter.boundingRect(QRect(QPoint(0, 0), viewport.size()), Qt.AlignLeft, "Q") for i, line in enumerate(lines): painter.drawText(10, (i + 1) * textRect.height(), line) self.log(line) # diagonal painter.drawLine( QPointF(0, 0), QPointF(painter.viewport().width(), painter.viewport().height())) painter.drawLine(QPointF(painter.viewport().width(), 0), QPointF(0, painter.viewport().height())) # credit label margin, paddingH, paddingV = (3, 4, 3) credit = "This is credit" rect = QRect(0, 0, painter.viewport().width() - margin, painter.viewport().height() - margin) textRect = painter.boundingRect(rect, Qt.AlignBottom | Qt.AlignRight, credit) bgRect = QRect(textRect.left() - paddingH, textRect.top() - paddingV, textRect.width() + 2 * paddingH, textRect.height() + 2 * paddingV) painter.drawRect(bgRect) painter.drawText(rect, Qt.AlignBottom | Qt.AlignRight, credit)