Example #1
0
    def __init__(self, table, parent=None):
        TableDataModel.__init__(self, table, parent)

        self.layer = None

        if isinstance(table, LVectorTable):
            self.layer = VLayerRegistry.instance().getLayer(table.name)
        else:
            self.layer = VLayerRegistry.instance().getLayer(table)

        if not self.layer:
            return
        # populate self.resdata
        self.resdata = []
        for f in self.layer.getFeatures():
            a = f.attributes()
            # add the geometry type
            if f.hasGeometry():
                a.append(QgsWkbTypes.displayString(f.geometry().wkbType()))
            else:
                a.append('None')
            self.resdata.append(a)

        self.fetchedFrom = 0
        self.fetchedCount = len(self.resdata)
Example #2
0
    def _openShapefile(self):
        layer = QgsVectorLayer(self.shapePath, self.fileName, "ogr")

        wkbType = layer.wkbType()
        if wkbType != QgsWkbTypes.PointZ:
            self.importError.emit(
                self.tr("File has incorrect WKB type '{}'. Please select layer "
                        "with 'PointZ' WKB type.".format(QgsWkbTypes.displayString(wkbType))))
            return None

        return layer
Example #3
0
 def convertToLineStrings(self, geom):
     if QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.PointGeometry:
         raise QgsProcessingException(
             self.tr('Cannot convert from {0} to LineStrings').format(QgsWkbTypes.displayString(geom.wkbType())))
     elif QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.LineGeometry:
         if QgsWkbTypes.isMultiType(geom.wkbType()):
             return geom.asGeometryCollection()
         else:
             #line to line
             return [geom]
     else:
         # polygons to lines
         # we just use the boundary here - that consists of all rings in the (multi)polygon
         boundary = QgsGeometry(geom.constGet().boundary())
         # boundary will be multipart
         return boundary.asGeometryCollection()
Example #4
0
 def convertToMultiLineStrings(self, geom):
     if QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.PointGeometry:
         raise QgsProcessingException(
             self.tr('Cannot convert from {0} to MultiLineStrings').format(QgsWkbTypes.displayString(geom.wkbType())))
     elif QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.LineGeometry:
         if QgsWkbTypes.isMultiType(geom.wkbType()):
             return [geom]
         else:
             # line to multiLine
             ml = QgsMultiLineString()
             ml.addGeometry(geom.constGet().clone())
             return [QgsGeometry(ml)]
     else:
         # polygons to multilinestring
         # we just use the boundary here - that consists of all rings in the (multi)polygon
         return [QgsGeometry(geom.constGet().boundary())]
Example #5
0
 def convertToMultiLineStrings(self, geom):
     if QgsWkbTypes.geometryType(
             geom.wkbType()) == QgsWkbTypes.PointGeometry:
         raise QgsProcessingException(
             self.tr('Cannot convert from {0} to MultiLineStrings').format(
                 QgsWkbTypes.displayString(geom.wkbType())))
     elif QgsWkbTypes.geometryType(
             geom.wkbType()) == QgsWkbTypes.LineGeometry:
         if QgsWkbTypes.isMultiType(geom.wkbType()):
             return [geom]
         else:
             # line to multiLine
             ml = QgsMultiLineString()
             ml.addGeometry(geom.constGet().clone())
             return [QgsGeometry(ml)]
     else:
         # polygons to multilinestring
         # we just use the boundary here - that consists of all rings in the (multi)polygon
         return [QgsGeometry(geom.constGet().boundary())]
Example #6
0
 def convertToLineStrings(self, geom):
     if QgsWkbTypes.geometryType(
             geom.wkbType()) == QgsWkbTypes.PointGeometry:
         raise QgsProcessingException(
             self.tr('Cannot convert from {0} to LineStrings').format(
                 QgsWkbTypes.displayString(geom.wkbType())))
     elif QgsWkbTypes.geometryType(
             geom.wkbType()) == QgsWkbTypes.LineGeometry:
         if QgsWkbTypes.isMultiType(geom.wkbType()):
             return geom.asGeometryCollection()
         else:
             #line to line
             return [geom]
     else:
         # polygons to lines
         # we just use the boundary here - that consists of all rings in the (multi)polygon
         boundary = QgsGeometry(geom.constGet().boundary())
         # boundary will be multipart
         return boundary.asGeometryCollection()
Example #7
0
    def createLayer(cls, topicName, rosMessages=None, extraProperties=None, subscribe=False, keepOlderMessages=False,
                    sampleInterval=1):
        if rosMessages:
            # Features were passed in, so it's a static data layer.
            geomType = QgsWkbTypes.displayString(cls.geomType)  # Get string version of geomtype enum.
            uri = '{}?crs=PROJ4:{}'.format(geomType, proj4CrsDict[cls.crsName])
            layer = QgsVectorLayer(uri, topicName, 'memory')

            # Convert from ROS messages to GeoJSON Features to QgsFeatures.
            features = []
            for n, m in enumerate(rosMessages):
                translatedFeatures = cls.translate(m)  # Append one or more features.

                # Optionally merge extra properties like bag timestamps in to features created by this message.
                if extraProperties is not None:
                    for f in translatedFeatures:
                        f['properties'].update(extraProperties[n])

                features += translatedFeatures

            qgsFeatures, fields = featuresToQgs(features)
            layer.dataProvider().addAttributes(fields)
            layer.dataProvider().addFeatures(qgsFeatures)
            layer.updateFields()  # Required, otherwise the layer will not re-read field metadata.
            return layer
        else:
            # No features, it must be a ROS topic to get data from.
            uri = '{}?type={}&index=no&subscribe={}&keepOlderMessages={}&sampleInterval={}&crsName={}'.format(
                topicName,
                cls.messageType._type,
                subscribe,
                keepOlderMessages,
                sampleInterval,
                cls.crsName,
            )
            layer = QgsVectorLayer(uri, topicName, 'rosvectorprovider')

            # Need to monitor when data is changed and call updateFields in order to capture the new fields
            # that are discovered on the first and possibly future messages. Without this, the layer will never
            # expose any of the field data available.
            # TODO: Find a cleaner way to signal this update and only call it when actual field changes occur.
            layer.dataChanged.connect(layer.updateFields)
            return layer
def copy_layer_into_memory_layer(source_layer, layer_name):

    source_provider = source_layer.dataProvider()

    uri = "{0}?crs=EPSG:{1}".format(
        QgsWkbTypes.displayString(source_provider.wkbType()).lstrip("WKB"),
        str(source_provider.crs().postgisSrid()),
    )

    dest_layer = QgsVectorLayer(uri, layer_name, "memory")
    dest_provider = dest_layer.dataProvider()

    dest_provider.addAttributes(source_provider.fields())
    dest_layer.updateFields()

    dest_provider.addFeatures([f for f in source_provider.getFeatures()])
    dest_layer.updateExtents()

    return dest_layer
Example #9
0
    def createShp(self, out_shp, features, inLayer, sr, out_type=None):
        self.new_name = inLayer.name() + "_new"
        self.geomType = QgsWkbTypes.displayString(inLayer.wkbType())
        if out_type == "m":
            self.new_shp = QgsVectorLayer(self.geomType, self.new_name,
                                          "memory")
            self.pr = self.new_shp.dataProvider()

            self.fields = [
                QgsField(n, t) for t, n, _ in features[0]["properties"]
            ]
            self.pr.addAttributes(self.fields)
            self.new_shp.updateFields()

            for f in features:
                self.feat = QgsFeature()
                self.feat.setGeometry(f["geometry"])
                self.attr = [k for i, j, k in f["properties"]]
                self.feat.setAttributes(self.attr)
                self.pr.addFeature(self.feat)
                self.new_shp.updateExtents()
            QgsProject.instance().addMapLayer(self.new_shp)
            self.new_shp.setCrs(QgsCoordinateReferenceSystem.fromWkt(sr))

        else:
            self.fields = QgsFields()
            for t, n, _ in features[0]["properties"]:
                self.fields.append(QgsField(n, t))

            self.writer = QgsVectorFileWriter(
                out_shp, 'UTF-8', self.fields, inLayer.wkbType(),
                QgsCoordinateReferenceSystem.fromWkt(sr), 'ESRI Shapefile')
            for f in features:
                self.feat = QgsFeature()
                self.feat.setGeometry(f["geometry"])
                self.attr = [k for i, j, k in f["properties"]]
                self.feat.setAttributes(self.attr)
                self.writer.addFeature(self.feat)

            self.layer = iface.addVectorLayer(out_shp, '', 'ogr')
            self.layer.setExtent(inLayer.extent())
            del (self.writer)
Example #10
0
    def prepareNewLayer(self, currLayer, newLayerName, geomWkbType, reqFields):

        currCrs = currLayer.crs().authid()
        #print ('---------- layer CRS: {}'.format(currCrs))
        TOMsMessageLog.logMessage('---------- layer CRS: {}'.format(currCrs),
                                  level=Qgis.Info)
        #currCrs = 'EPSG:27700'
        """newLayer = QgsVectorLayer("{type}?={crs}".format(type=geomType,
                                                         crs='EPSG:27700'), newLayerName, "memory")"""
        newLayer = QgsVectorLayer(
            "{type}?crs={crs}".format(
                type=QgsWkbTypes.displayString(geomWkbType), crs=currCrs),
            newLayerName, "memory")

        #newFields = self.setFieldsForTOMsExportLayer(currLayer, reqFields)
        newLayer.dataProvider().addAttributes(reqFields)
        #newLayer.reload()
        newLayer.updateFields()

        return newLayer
Example #11
0
    def __init__(self, qgis_layer, client_var, relation_id=None, lock=None, **kwargs):
        """Constructor

        :param qgis_layer: the QGIS vector layer
        :type qgis_layer: QgsVectorLayer
        :param client_var: layer original name
        :type client_var: str
        :param relation_id: relation id, defaults to None
        :type relation_id: str, optional
        :param lock: [description], defaults to None
        :type lock: [type], optional
        """
        self.qgis_layer = qgis_layer
        self.geometry_type = QgsWkbTypes.displayString(qgis_layer.wkbType())
        self.client_var = client_var
        self.relation_id = relation_id
        self.lock = lock

        for k, v in list(kwargs.items()):
            setattr(self, k, v)
Example #12
0
 def convertToPolygon(self, geom):
     if QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.PointGeometry and geom.constGet().nCoordinates() < 3:
         raise QgsProcessingException(
             self.tr('Cannot convert from Point to Polygon').format(QgsWkbTypes.displayString(geom.wkbType())))
     elif QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.PointGeometry:
         # multipoint with at least 3 points
         # TODO: mega inefficient - needs rework when geometry iterators land
         # (but at least it doesn't lose Z/M values)
         points = []
         for g in geom.constGet().coordinateSequence():
             for r in g:
                 for p in r:
                     points.append(p)
         linestring = QgsLineString(points)
         linestring.close()
         p = QgsPolygon()
         p.setExteriorRing(linestring)
         return [QgsGeometry(p)]
     elif QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.LineGeometry:
         if QgsWkbTypes.isMultiType(geom):
             parts = []
             for i in range(geom.constGet().numGeometries()):
                 p = QgsPolygon()
                 linestring = geom.constGet().geometryN(i).clone()
                 linestring.close()
                 p.setExteriorRing(linestring)
                 parts.append(QgsGeometry(p))
             return QgsGeometry.collectGeometry(parts)
         else:
             # linestring to polygon
             p = QgsPolygon()
             linestring = geom.constGet().clone()
             linestring.close()
             p.setExteriorRing(linestring)
             return [QgsGeometry(p)]
     else:
         #polygon
         if QgsWkbTypes.isMultiType(geom):
             return geom.asGeometryCollection()
         else:
             return [geom]
Example #13
0
 def convertToPolygon(self, geom):
     if QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.PointGeometry and geom.constGet().nCoordinates() < 3:
         raise QgsProcessingException(
             self.tr('Cannot convert from Point to Polygon').format(QgsWkbTypes.displayString(geom.wkbType())))
     elif QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.PointGeometry:
         # multipoint with at least 3 points
         # TODO: mega inefficient - needs rework when geometry iterators land
         # (but at least it doesn't lose Z/M values)
         points = []
         for g in geom.constGet().coordinateSequence():
             for r in g:
                 for p in r:
                     points.append(p)
         linestring = QgsLineString(points)
         linestring.close()
         p = QgsPolygon()
         p.setExteriorRing(linestring)
         return [QgsGeometry(p)]
     elif QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.LineGeometry:
         if QgsWkbTypes.isMultiType(geom):
             parts = []
             for i in range(geom.constGet().numGeometries()):
                 p = QgsPolygon()
                 linestring = geom.constGet().geometryN(i).clone()
                 linestring.close()
                 p.setExteriorRing(linestring)
                 parts.append(QgsGeometry(p))
             return QgsGeometry.collectGeometry(parts)
         else:
             # linestring to polygon
             p = QgsPolygon()
             linestring = geom.constGet().clone()
             linestring.close()
             p.setExteriorRing(linestring)
             return [QgsGeometry(p)]
     else:
         #polygon
         if QgsWkbTypes.isMultiType(geom):
             return geom.asGeometryCollection()
         else:
             return [geom]
Example #14
0
    def test_zm(self):
        """Test regression GH #43268"""

        md = QgsProviderRegistry.instance().providerMetadata('postgres')
        conn = md.createConnection(self.uri, {})
        sql = """
        DROP TABLE IF EXISTS qgis_test.gh_43268_test_zm;
        CREATE TABLE qgis_test.gh_43268_test_zm (geom geometry(GeometryZ));
        INSERT INTO qgis_test.gh_43268_test_zm (geom) VALUES
            ('POINT(0 0 0)'),
            ('LINESTRING(0 0 0, 0 0 0)'),
            ('POLYGON((0 0 0, 0 0 0, 0 0 0, 0 0 0))');
        """
        conn.executeSql(sql)

        table_info = conn.table('qgis_test', 'gh_43268_test_zm')
        self.assertEqual(
            sorted([
                QgsWkbTypes.displayString(col.wkbType)
                for col in table_info.geometryColumnTypes()
            ]), ['LineStringZ', 'PointZ', 'PolygonZ'])
Example #15
0
    def createMemLayer(self, featureIterator):
        # create a memory layer, given a feature type and the features that go in it
        fields, geomAtt = self._fields()
        layerName = self.featureType.featureTypeName
        if geomAtt is None:
            uri = "None"
        else:
            uri = "{}?crs={}".format(
                QgsWkbTypes.displayString(
                    FeatureTypeHelper.typeNameConverter[geomAtt.type.lower()]),
                geomAtt.SRS)
        newlayer = QgsVectorLayer(uri, layerName, 'memory')

        with edit(newlayer):
            newlayer.dataProvider().addAttributes(fields)
            newlayer.updateFields()
            features = list(featureIterator)
            newlayer.addFeatures(features)
            if geomAtt is not None:
                newlayer.setCrs(QgsCoordinateReferenceSystem(geomAtt.SRS))
        return newlayer
Example #16
0
    def load_from_qnode(cls, qnode):
        meta = qnode.customProperty("xyz-hub")
        conn_info = qnode.customProperty("xyz-hub-conn")
        tags = qnode.customProperty("xyz-hub-tags")
        unique = qnode.customProperty("xyz-hub-id")
        name = qnode.name()
        meta = json.loads(meta)
        conn_info = json.loads(conn_info)
        conn_info = SpaceConnectionInfo.from_dict(conn_info)

        obj = cls(conn_info, meta, tags=tags, unique=unique, group_name=name)
        obj.qgroups["main"] = qnode
        for g in qnode.findGroups():
            obj.qgroups[g.name()] = g
            lst_vlayers = [i.layer() for i in g.findLayers()]
            for vlayer in lst_vlayers:
                geom_str = QgsWkbTypes.displayString(vlayer.wkbType())
                obj.map_vlayer.setdefault(geom_str, list()).append(vlayer)
                obj.map_fields.setdefault(geom_str, list()).append(vlayer.fields())
                
        return obj
Example #17
0
    def test_saveLayerToGpkg(self):
        testLayerA = QgsVectorLayer(('{type}?crs=epsg:27700&index=yes'.format(
            type=QgsWkbTypes.displayString(QgsWkbTypes.MultiLineString))),
                                    'testA', 'memory')
        self.assertEqual(testLayerA.wkbType(), QgsWkbTypes.MultiLineString)
        #print ('++++++ testLayerA type: {}'.format(QgsWkbTypes.displayString(testLayerA.wkbType())))

        testProviderA = testLayerA.dataProvider()

        testLineString1 = QgsGeometry.fromPolylineXY(
            [QgsPointXY(0, 0), QgsPointXY(1, 0)])

        testProviderA.addAttributes([
            QgsField("GeometryID", QVariant.String),
            QgsField("RestrictionTypeID", QVariant.Int),
            QgsField("GeomShapeID", QVariant.Int),
            QgsField("AzimuthToRoadCentreLine", QVariant.Double)
        ])
        testFieldsA = testProviderA.fields()
        """for field in testFields:
            print ('** {}'.format(field.name()))"""

        testFeature1 = QgsFeature(testFieldsA)
        testFeature1.setGeometry(testLineString1)
        testFeature1.setAttributes(["Smith", 101, 1, 0])
        testProviderA.addFeatures([testFeature1])
        testLayerA.reload()

        fileName = 'C:\\Users\\marie_000\\Documents\\MHTC\\tmp\\test1.gpkg'
        self.testClass.saveLayerToGpkg(testLayerA, fileName)

        ds = ogr.Open(fileName)
        lyr = ds.GetLayerByName('testA')
        self.assertIsNotNone(lyr)
        f = lyr.GetNextFeature()
        self.assertEqual(f['GeometryID'], 'Smith')
Example #18
0
    def test_processLayer(self):
        testLayerA = QgsVectorLayer(('{type}?crs=epsg:27700&index=yes'.format(
            type=QgsWkbTypes.displayString(QgsWkbTypes.MultiLineString))),
                                    'testA', 'memory')
        self.assertEqual(testLayerA.wkbType(), QgsWkbTypes.MultiLineString)
        # print ('++++++ testLayerA type: {}'.format(QgsWkbTypes.displayString(testLayerA.wkbType())))

        testProviderA = testLayerA.dataProvider()

        testLineString1 = QgsGeometry.fromPolylineXY(
            [QgsPointXY(0, 0), QgsPointXY(1, 0)])

        testProviderA.addAttributes([
            QgsField("GeometryID", QVariant.String),
            QgsField("RestrictionTypeID", QVariant.Int),
            QgsField("GeomShapeID", QVariant.Int),
            QgsField("AzimuthToRoadCentreLine", QVariant.Double)
        ])
        testFieldsA = testProviderA.fields()
        """for field in testFields:
            print ('** {}'.format(field.name()))"""

        testFeature1 = QgsFeature(testFieldsA)
        testFeature1.setGeometry(testLineString1)
        testFeature1.setAttributes(["Smith", 101, 1, 0])
        testProviderA.addFeatures([testFeature1])
        testLayerA.reload()

        requiredFields = ["GeometryID", "RestrictionTypeID"]
        outputLayersList = self.testClass.processLayer(testLayerA,
                                                       requiredFields)
        self.assertEqual(len(outputLayersList), 1)
        self.assertEqual(len(outputLayersList[0][1].fields()), 2)

        # TODO: Need to include tests for relations - finding lookup fields and returning values ...
        """ Cases are:
Example #19
0
    def response_data_mode(self, request, export_features=False):
        """
        Query layer and return data
        :param request: DjangoREST API request object
        :param formatter: Boolean, default False, True for to use QgsJsonExport.exportFeatures method
        :return: response dict data
        """

        # Create the QGIS feature request, it will be passed through filters
        # and to the final QGIS API get features call.
        qgis_feature_request = QgsFeatureRequest()

        # Prepare arguments for the get feature call
        kwargs = {}

        # Apply filter backends, store original subset string
        original_subset_string = self.metadata_layer.qgis_layer.subsetString()
        if hasattr(self, 'filter_backends'):
            try:
                for backend in self.filter_backends:
                    backend().apply_filter(request, self.metadata_layer,
                                           qgis_feature_request, self)
            except Exception as e:
                raise APIException(e)

        # Paging cannot be a backend filter
        if 'page' in request.query_params:
            kwargs['page'] = request.query_params.get('page')
            kwargs['page_size'] = request.query_params.get('page_size', 10)

        # Make sure we have all attrs we need to build the server FID
        provider = self.metadata_layer.qgis_layer.dataProvider()
        if qgis_feature_request.flags() & QgsFeatureRequest.SubsetOfAttributes:
            attrs = qgis_feature_request.subsetOfAttributes()
            for attr_idx in provider.pkAttributeIndexes():
                if attr_idx not in attrs:
                    attrs.append(attr_idx)
            qgis_feature_request.setSubsetOfAttributes(attrs)

        self.features = get_qgis_features(self.metadata_layer.qgis_layer,
                                          qgis_feature_request, **kwargs)

        # Reproject feature if layer CRS != Project CRS
        if self.reproject:
            for f in self.features:
                self.reproject_feature(f)

        ex = QgsJsonExporter(self.metadata_layer.qgis_layer)

        # If 'unique' request params is set,
        # api return a list of unique
        # field name sent with 'unique' param.
        # --------------------------------------
        # IDEA:     for big data it'll be iterate over features to get unique
        #           c++ iteration is fast. Instead memory layer with too many features can be a problem.
        if 'unique' in request.query_params:

            vl = QgsVectorLayer(
                QgsWkbTypes.displayString(
                    self.metadata_layer.qgis_layer.wkbType()),
                "temporary_vector", "memory")
            pr = vl.dataProvider()

            # add fields
            pr.addAttributes(self.metadata_layer.qgis_layer.fields())
            vl.updateFields(
            )  # tell the vector layer to fetch changes from the provider

            res = pr.addFeatures(self.features)

            uniques = vl.uniqueValues(
                self.metadata_layer.qgis_layer.fields().indexOf(
                    request.query_params.get('unique')))

            values = []
            for u in uniques:
                try:
                    if u:
                        values.append(json.loads(QgsJsonUtils.encodeValue(u)))
                except Exception as e:
                    logger.error(f'Response vector widget unique: {e}')
                    continue

            # sort values
            values.sort()
            self.results.update({'data': values, 'count': len(values)})

            del (vl)

        else:

            ex.setTransformGeometries(False)

            # check for formatter query url param and check if != 0
            if 'formatter' in request.query_params:
                formatter = request.query_params.get('formatter')
                if formatter.isnumeric() and int(formatter) == 0:
                    export_features = False
                else:
                    export_features = True

            if export_features:
                feature_collection = json.loads(
                    ex.exportFeatures(self.features))
            else:

                # to exclude QgsFormater used into QgsJsonExporter is necessary build by hand single json feature
                ex.setIncludeAttributes(False)

                feature_collection = {
                    'type': 'FeatureCollection',
                    'features': []
                }

                for feature in self.features:
                    fnames = []
                    date_fields = []
                    for f in feature.fields():
                        fnames.append(f.name())
                        if f.typeName() in ('date', 'datetime', 'time'):
                            date_fields.append(f)

                    jsonfeature = json.loads(
                        ex.exportFeature(
                            feature, dict(zip(fnames, feature.attributes()))))

                    # Update date and datetime fields value if widget is active
                    if len(date_fields) > 0:
                        for f in date_fields:
                            field_idx = self.metadata_layer.qgis_layer.fields(
                            ).indexFromName(f.name())
                            options = self.metadata_layer.qgis_layer.editorWidgetSetup(
                                field_idx).config()
                            if 'field_iso_format' in options and not options[
                                    'field_iso_format']:
                                try:
                                    jsonfeature['properties'][f.name()] = feature.attribute(f.name())\
                                        .toString(options['field_format'])
                                except:
                                    pass

                    feature_collection['features'].append(jsonfeature)

            # Change media
            self.change_media(feature_collection)

            # Patch feature IDs with server featureIDs
            fids_map = {}
            for f in self.features:
                fids_map[f.id()] = server_fid(f, provider)

            for i in range(len(feature_collection['features'])):
                f = feature_collection['features'][i]
                f['id'] = fids_map[f['id']]

            self.results.update(
                APIVectorLayerStructure(
                    **{
                        'data':
                        feature_collection,
                        'count':
                        count_qgis_features(self.metadata_layer.qgis_layer,
                                            qgis_feature_request, **kwargs),
                        'geometryType':
                        self.metadata_layer.geometry_type,
                    }).as_dict())

            # FIXME: add extra fields data by signals and receivers
            # FIXME: featurecollection = post_serialize_maplayer.send(layer_serializer, layer=self.layer_name)
            # FIXME: Not sure how to map this to the new QGIS API

        # Restore the original subset string
        self.metadata_layer.qgis_layer.setSubsetString(original_subset_string)
Example #20
0
    def __init__(self, destination, encoding, fields, geometryType,
                 crs, options=None):
        self.destination = destination
        self.isNotFileBased = False
        self.layer = None
        self.writer = None

        if encoding is None:
            settings = QSettings()
            encoding = settings.value('/Processing/encoding', 'System', str)

        if self.destination.startswith(self.MEMORY_LAYER_PREFIX):
            self.isNotFileBased = True

            uri = QgsWkbTypes.displayString(geometryType) + "?uuid=" + str(uuid.uuid4())
            if crs.isValid():
                uri += '&crs=' + crs.authid()
            fieldsdesc = []
            for f in fields:
                qgsfield = _toQgsField(f)
                fieldsdesc.append('field=%s:%s' % (qgsfield.name(),
                                                   TYPE_MAP_MEMORY_LAYER.get(qgsfield.type(), "string")))
            if fieldsdesc:
                uri += '&' + '&'.join(fieldsdesc)

            self.layer = QgsVectorLayer(uri, self.destination, 'memory')
            self.writer = self.layer.dataProvider()
        elif self.destination.startswith(self.POSTGIS_LAYER_PREFIX):
            self.isNotFileBased = True
            uri = QgsDataSourceUri(self.destination[len(self.POSTGIS_LAYER_PREFIX):])
            connInfo = uri.connectionInfo()
            (success, user, passwd) = QgsCredentials.instance().get(connInfo, None, None)
            if success:
                QgsCredentials.instance().put(connInfo, user, passwd)
            else:
                raise GeoAlgorithmExecutionException("Couldn't connect to database")
            try:
                db = postgis.GeoDB(host=uri.host(), port=int(uri.port()),
                                   dbname=uri.database(), user=user, passwd=passwd)
            except postgis.DbError as e:
                raise GeoAlgorithmExecutionException(
                    "Couldn't connect to database:\n%s" % e.message)

            def _runSQL(sql):
                try:
                    db._exec_sql_and_commit(str(sql))
                except postgis.DbError as e:
                    raise GeoAlgorithmExecutionException(
                        'Error creating output PostGIS table:\n%s' % e.message)

            fields = [_toQgsField(f) for f in fields]
            fieldsdesc = ",".join('%s %s' % (f.name(),
                                             TYPE_MAP_POSTGIS_LAYER.get(f.type(), "VARCHAR"))
                                  for f in fields)

            _runSQL("CREATE TABLE %s.%s (%s)" % (uri.schema(), uri.table().lower(), fieldsdesc))
            if geometryType != QgsWkbTypes.NullGeometry:
                _runSQL("SELECT AddGeometryColumn('{schema}', '{table}', 'the_geom', {srid}, '{typmod}', 2)".format(
                    table=uri.table().lower(), schema=uri.schema(), srid=crs.authid().split(":")[-1],
                    typmod=QgsWkbTypes.displayString(geometryType).upper()))

            self.layer = QgsVectorLayer(uri.uri(), uri.table(), "postgres")
            self.writer = self.layer.dataProvider()
        elif self.destination.startswith(self.SPATIALITE_LAYER_PREFIX):
            self.isNotFileBased = True
            uri = QgsDataSourceUri(self.destination[len(self.SPATIALITE_LAYER_PREFIX):])
            try:
                db = spatialite.GeoDB(uri=uri)
            except spatialite.DbError as e:
                raise GeoAlgorithmExecutionException(
                    "Couldn't connect to database:\n%s" % e.message)

            def _runSQL(sql):
                try:
                    db._exec_sql_and_commit(str(sql))
                except spatialite.DbError as e:
                    raise GeoAlgorithmExecutionException(
                        'Error creating output Spatialite table:\n%s' % str(e))

            fields = [_toQgsField(f) for f in fields]
            fieldsdesc = ",".join('%s %s' % (f.name(),
                                             TYPE_MAP_SPATIALITE_LAYER.get(f.type(), "VARCHAR"))
                                  for f in fields)

            _runSQL("DROP TABLE IF EXISTS %s" % uri.table().lower())
            _runSQL("CREATE TABLE %s (%s)" % (uri.table().lower(), fieldsdesc))
            if geometryType != QgsWkbTypes.NullGeometry:
                _runSQL("SELECT AddGeometryColumn('{table}', 'the_geom', {srid}, '{typmod}', 2)".format(
                    table=uri.table().lower(), srid=crs.authid().split(":")[-1],
                    typmod=QgsWkbTypes.displayString(geometryType).upper()))

            self.layer = QgsVectorLayer(uri.uri(), uri.table(), "spatialite")
            self.writer = self.layer.dataProvider()
        else:
            formats = QgsVectorFileWriter.supportedFiltersAndFormats()
            OGRCodes = {}
            for (key, value) in list(formats.items()):
                extension = str(key)
                extension = extension[extension.find('*.') + 2:]
                extension = extension[:extension.find(' ')]
                OGRCodes[extension] = value
            OGRCodes['dbf'] = "DBF file"

            extension = self.destination[self.destination.rfind('.') + 1:]

            if extension not in OGRCodes:
                extension = 'shp'
                self.destination = self.destination + '.shp'

            if geometryType == QgsWkbTypes.NoGeometry:
                if extension == 'shp':
                    extension = 'dbf'
                    self.destination = self.destination[:self.destination.rfind('.')] + '.dbf'
                if extension not in self.nogeometry_extensions:
                    raise GeoAlgorithmExecutionException(
                        "Unsupported format for tables with no geometry")

            qgsfields = QgsFields()
            for field in fields:
                qgsfields.append(_toQgsField(field))

            # use default dataset/layer options
            dataset_options = QgsVectorFileWriter.defaultDatasetOptions(OGRCodes[extension])
            layer_options = QgsVectorFileWriter.defaultLayerOptions(OGRCodes[extension])

            self.writer = QgsVectorFileWriter(self.destination, encoding,
                                              qgsfields, geometryType, crs, OGRCodes[extension],
                                              dataset_options, layer_options)
Example #21
0
    def handle_add_layer(self):
        """Create a new layer by name (rev_lyr)"""

        slds = self.get_sld()

        selected_name = self.dlg.mComboBox.currentText()
        selected_id = self.dataset_dictionary[selected_name]

        # Group name equals selected dataset name
        group = self.create_group(selected_name)

        # Get metadata and features from NgisOpenAPI
        try:
            metadata_from_api = self.client.getDatasetMetadata(selected_id)
            epsg = metadata_from_api.crs_epsg
            features_from_api = self.client.getDatasetFeatures(
                metadata_from_api.id, metadata_from_api.bbox, epsg)
        except Exception as e:
            error = ApiError("Nedlasting av data mislyktes",
                             "Kunne ikke laste ned datasett", e)
            self.iface.messageBar().pushMessage(error.title,
                                                error.detail,
                                                error.show_more,
                                                level=2,
                                                duration=10)
            return
        crs_from_api = features_from_api['crs']['properties']['name']
        features_by_type = {}

        # Extract features from GeoJSON into dictionary
        for feature in features_from_api['features']:
            feature_type = feature['properties']['featuretype']
            features_by_type.setdefault(feature_type, []).append(feature)

        features_from_api['features'] = None

        for feature_type, features_list in features_by_type.items():
            # Create a new GeoJSON object containing a single featuretype
            features_dict = features_from_api.copy()
            features_dict['features'] = features_list

            features_json = json.dumps(features_dict, ensure_ascii=False)

            # Identify fields and features from GeoJSON
            codec = QTextCodec.codecForName("UTF-8")
            fields = QgsJsonUtils.stringToFields(features_json, codec)
            newFeatures = QgsJsonUtils.stringToFeatureList(
                features_json, fields, codec)

            # If different geometry types are identified, separate them into individual layers
            geometry_dict = {}
            if newFeatures:
                for feature in newFeatures:

                    featuretype = feature.attribute('featuretype')
                    geom_type = feature.geometry()
                    geom_type = QgsWkbTypes.displayString(
                        int(geom_type.wkbType()))
                    if geom_type not in geometry_dict:
                        geometry_dict[geom_type] = {}
                    if featuretype not in geometry_dict[geom_type]:
                        geometry_dict[geom_type][featuretype] = []

                    geometry_dict[geom_type][featuretype].append(feature)

            for geom_type, feature_types in geometry_dict.items():
                for feature_type, features in feature_types.items():
                    lyr = QgsVectorLayer(f'{geom_type}?crs={crs_from_api}',
                                         f'{feature_type}-{geom_type}',
                                         "memory")
                    #lyr = QgsVectorLayer(f'{geom_type}?crs=EPSG:25832', f'{feature_type}-{geom_type}', "memory") #TODO Remove
                    QgsProject.instance().addMapLayer(lyr, False)

                    lyr.startEditing()

                    add_fields_to_layer(lyr, fields, feature_type)

                    lyr.commitChanges()
                    l_d = lyr.dataProvider()
                    l_d.addFeatures(features)
                    # update the extent of rev_lyr
                    lyr.updateExtents()
                    # save changes made in 'rev_lyr'
                    lyr.commitChanges()
                    group.addLayer(lyr)

                    #lyr.committedFeaturesAdded.connect(self.handleCommitedAddedFeatures)
                    #lyr.committedFeaturesRemoved.connect(self.handleCommittedFeaturesRemoved)
                    #lyr.featuresDeleted.connect(self.handleDeletedFeatures)
                    #lyr.committedGeometriesChanges(self.ee)

                    lyr.beforeCommitChanges.connect(
                        self.handle_before_commitchanges)

                    if feature_type in slds:
                        lyr.loadSldStyle(slds[feature_type])

                    self.dataset_dictionary[lyr.id()] = selected_id
                    self.feature_type_dictionary[lyr.id()] = feature_type
    def processAlgorithm(self, parameters, context, feedback):
        """
        Here is where the processing itself takes place.
        """
        
        i_fields = self.parameterAsMatrix(
            parameters,
            self.INPUT_F,
            context)
        
        #CREA TABELLA CONTENUTI PROGETTO
        #per altri campi occorre vedere quali si serve aggiungere
        
        #funzione iterativa per posizione layer nella TOC
        def get_group_layers(group, level):
            level = level + group.name() + ' - '#' >> '
            for child in group.children():
                if isinstance(child, QgsLayerTreeGroup):
                    get_group_layers(child, level)
                else:
                    TOC_dict [child.name()] = level
                    #print(lev)
                    
        #dizionario delle posizioni
        TOC_dict ={}
        
        root = QgsProject.instance().layerTreeRoot()
        for child in root.children():
            level = 'root - ' #' >> '
            if isinstance(child, QgsLayerTreeGroup):
                get_group_layers(child, level)
            elif isinstance(child, QgsLayerTreeLayer):
                #lev = level #+ child.name())
                TOC_dict[child.name()] = level
        
        #abort if TOC is empty
        #feedback.pushInfo (str(TOC_dict))
        #feedback.pushInfo (str(not bool(TOC_dict)))
        
        if not bool(TOC_dict):
            raise QgsProcessingException('Invalid input value: EMPY PROJECT')
            
        
        #parametro denominazione tabella risultante
        report = 'Project_Layers_Table'
		
        fields = QgsFields()
        
        for item in i_fields:
            if item in ('Layer_N','Geometry_Not_Valid','Layer_Type','Layer_Feature_Count'):
                fields.append(QgsField(item, QVariant.Int))
            else:
                fields.append(QgsField(item, QVariant.String))
        
        
        (sink, dest_id) = self.parameterAsSink(
            parameters,
            self.OUTPUT,
            context, fields)
        
        # If sink was not created, throw an exception to indicate that the algorithm
        # encountered a fatal error. The exception text can be any string, but in this
        # case we use the pre-built invalidSinkError method to return a standard
        # helper text for when a sink cannot be evaluated
        if sink is None:
            raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) 
            
        feat = QgsFeature()
        count = 1
        
        for layer in QgsProject.instance().mapLayers().values():
            if layer.name().find("Project_Layers_Table") == -1:
                Layer_N = count
                count += 1
                Layer_Name = layer.name()
                Layer_Group_Level = TOC_dict.get(Layer_Name)
                Layer_Crs = layer.crs().authid()
                Layer_Source = layer.source()
                Layer_Meta_Parent_Id = layer.metadata().parentIdentifier()
                Layer_Meta_Identifier = layer.metadata().identifier()
                Layer_Meta_Title = layer.metadata().title()
                Layer_Meta_Type = layer.metadata().type()
                Layer_Meta_Language = layer.metadata().language()
                Layer_Meta_Abstract = layer.metadata().abstract()
                Raster_type = Raster_data_type = Raster_Info_dim =  '-'
                Raster_extent = Raster_Info_res = Raster_NoDataValue = '-'
                
                if layer.type() is not QgsMapLayerType.RasterLayer:
                    Layer_Feature_Count = layer.featureCount()
                    Layer_Type = layer.wkbType()
                    Layer_Storage = layer.storageType()
                    Layer_Type_Name = QgsWkbTypes.displayString(layer.wkbType())
                    
                    Geometry_Not_Valid = 0
                    for f in layer.getFeatures():
                        if not f.geometry().isGeosValid():
                            Geometry_Not_Valid += 1
                    
                else:
                    Layer_Type = (0)
                    Layer_Type_Name = QgsMapLayerType.RasterLayer.name
                    Layer_Storage = ''
                    Layer_Feature_Count = 'nan'
                    Geometry_Not_Valid = 0
                    gh = layer.height()
                    gw = layer.width()
                    Raster_extent = layer.extent().toString()
                    provider = layer.dataProvider()
                    
                    gpx = layer.rasterUnitsPerPixelX()
                    gpy = layer.rasterUnitsPerPixelY()
                    block = provider.block(1, layer.extent(),  gpy, gpx)
                    for band in range(1, layer.bandCount()+1):
                        #print('Band ', band, layer.dataProvider().sourceNoDataValue(band))
                        Raster_NoDataValue = Raster_NoDataValue + 'Band ' + str(band) + ': ' + str(layer.dataProvider().sourceNoDataValue(band)) + ' '
                        Raster_data_type = type(provider.sourceNoDataValue(band)).__name__
                        Raster_type = layer.renderer().type()
                    #feedback.pushInfo(str(gh)+' x '+str(gw)+' - '+ str(gpx)+' x '+str(gpy))  
                    Raster_Info_dim = str(gh) + ' x '+ str(gw)
                    Raster_Info_res = str(gpx) + ' x ' + str(gpy)
                       
                campi = []
                for item in i_fields:
                    campi.append(vars()[item])
                    
                feat.setAttributes(campi)
                sink.addFeature(feat, QgsFeatureSink.FastInsert)
        
        return {self.OUTPUT: dest_id}
Example #23
0
File: vector.py Project: rui88/QGIS
    def __init__(self,
                 destination,
                 encoding,
                 fields,
                 geometryType,
                 crs,
                 options=None):
        self.destination = destination
        self.isNotFileBased = False
        self.layer = None
        self.writer = None

        if encoding is None:
            settings = QSettings()
            encoding = settings.value('/Processing/encoding',
                                      'System',
                                      type=str)

        if self.destination.startswith(self.MEMORY_LAYER_PREFIX):
            self.isNotFileBased = True

            uri = QgsWkbTypes.displayString(geometryType) + "?uuid=" + str(
                uuid.uuid4())
            if crs.isValid():
                uri += '&crs=' + crs.authid()
            fieldsdesc = []
            for f in fields:
                qgsfield = _toQgsField(f)
                fieldsdesc.append(
                    'field=%s:%s' %
                    (qgsfield.name(),
                     TYPE_MAP_MEMORY_LAYER.get(qgsfield.type(), "string")))
            if fieldsdesc:
                uri += '&' + '&'.join(fieldsdesc)

            self.layer = QgsVectorLayer(uri, self.destination, 'memory')
            self.writer = self.layer.dataProvider()
        elif self.destination.startswith(self.POSTGIS_LAYER_PREFIX):
            self.isNotFileBased = True
            uri = QgsDataSourceUri(
                self.destination[len(self.POSTGIS_LAYER_PREFIX):])
            connInfo = uri.connectionInfo()
            (success, user,
             passwd) = QgsCredentials.instance().get(connInfo, None, None)
            if success:
                QgsCredentials.instance().put(connInfo, user, passwd)
            else:
                raise GeoAlgorithmExecutionException(
                    "Couldn't connect to database")
            # fix_print_with_import
            print(uri.uri())
            try:
                db = postgis.GeoDB(host=uri.host(),
                                   port=int(uri.port()),
                                   dbname=uri.database(),
                                   user=user,
                                   passwd=passwd)
            except postgis.DbError as e:
                raise GeoAlgorithmExecutionException(
                    "Couldn't connect to database:\n%s" % e.message)

            def _runSQL(sql):
                try:
                    db._exec_sql_and_commit(str(sql))
                except postgis.DbError as e:
                    raise GeoAlgorithmExecutionException(
                        'Error creating output PostGIS table:\n%s' % e.message)

            fields = [_toQgsField(f) for f in fields]
            fieldsdesc = ",".join(
                '%s %s' %
                (f.name(), TYPE_MAP_POSTGIS_LAYER.get(f.type(), "VARCHAR"))
                for f in fields)

            _runSQL("CREATE TABLE %s.%s (%s)" %
                    (uri.schema(), uri.table().lower(), fieldsdesc))
            if geometryType != QgsWkbTypes.NullGeometry:
                _runSQL(
                    "SELECT AddGeometryColumn('{schema}', '{table}', 'the_geom', {srid}, '{typmod}', 2)"
                    .format(table=uri.table().lower(),
                            schema=uri.schema(),
                            srid=crs.authid().split(":")[-1],
                            typmod=QgsWkbTypes.displayString(
                                geometryType).upper()))

            self.layer = QgsVectorLayer(uri.uri(), uri.table(), "postgres")
            self.writer = self.layer.dataProvider()
        elif self.destination.startswith(self.SPATIALITE_LAYER_PREFIX):
            self.isNotFileBased = True
            uri = QgsDataSourceUri(
                self.destination[len(self.SPATIALITE_LAYER_PREFIX):])
            # fix_print_with_import
            print(uri.uri())
            try:
                db = spatialite.GeoDB(uri=uri)
            except spatialite.DbError as e:
                raise GeoAlgorithmExecutionException(
                    "Couldn't connect to database:\n%s" % e.message)

            def _runSQL(sql):
                try:
                    db._exec_sql_and_commit(str(sql))
                except spatialite.DbError as e:
                    raise GeoAlgorithmExecutionException(
                        'Error creating output Spatialite table:\n%s' % str(e))

            fields = [_toQgsField(f) for f in fields]
            fieldsdesc = ",".join(
                '%s %s' %
                (f.name(), TYPE_MAP_SPATIALITE_LAYER.get(f.type(), "VARCHAR"))
                for f in fields)

            _runSQL("DROP TABLE IF EXISTS %s" % uri.table().lower())
            _runSQL("CREATE TABLE %s (%s)" % (uri.table().lower(), fieldsdesc))
            if geometryType != QgsWkbTypes.NullGeometry:
                _runSQL(
                    "SELECT AddGeometryColumn('{table}', 'the_geom', {srid}, '{typmod}', 2)"
                    .format(table=uri.table().lower(),
                            srid=crs.authid().split(":")[-1],
                            typmod=QgsWkbTypes.displayString(
                                geometryType).upper()))

            self.layer = QgsVectorLayer(uri.uri(), uri.table(), "spatialite")
            self.writer = self.layer.dataProvider()
        else:
            formats = QgsVectorFileWriter.supportedFiltersAndFormats()
            OGRCodes = {}
            for (key, value) in list(formats.items()):
                extension = str(key)
                extension = extension[extension.find('*.') + 2:]
                extension = extension[:extension.find(' ')]
                OGRCodes[extension] = value
            OGRCodes['dbf'] = "DBF file"

            extension = self.destination[self.destination.rfind('.') + 1:]

            if extension not in OGRCodes:
                extension = 'shp'
                self.destination = self.destination + '.shp'

            if geometryType == QgsWkbTypes.NoGeometry:
                if extension == 'shp':
                    extension = 'dbf'
                    self.destination = self.destination[:self.destination.
                                                        rfind('.')] + '.dbf'
                if extension not in self.nogeometry_extensions:
                    raise GeoAlgorithmExecutionException(
                        "Unsupported format for tables with no geometry")

            qgsfields = QgsFields()
            for field in fields:
                qgsfields.append(_toQgsField(field))

            # use default dataset/layer options
            dataset_options = QgsVectorFileWriter.defaultDatasetOptions(
                OGRCodes[extension])
            layer_options = QgsVectorFileWriter.defaultLayerOptions(
                OGRCodes[extension])

            self.writer = QgsVectorFileWriter(self.destination, encoding,
                                              qgsfields, geometryType, crs,
                                              OGRCodes[extension],
                                              dataset_options, layer_options)
Example #24
0
    def spatialInfo(self):
        ret = []
        if not self.table.geomType:
            return ret

        tbl = [(QApplication.translate("DBManagerPlugin",
                                       "Column:"), self.table.geomColumn),
               (QApplication.translate("DBManagerPlugin",
                                       "Geometry:"), self.table.geomType),
               (QApplication.translate("DBManagerPlugin",
                                       "Qgis Geometry type:"),
                QgsWkbTypes.displayString(self.table.wkbType))]

        # only if we have info from geometry_columns
        if self.table.geomDim:
            tbl.append(
                (QApplication.translate("DBManagerPlugin",
                                        "Dimension:"), self.table.geomDim))

        srid = self.table.srid if self.table.srid else -1
        if srid != -1:
            sr_info = (self.table.database().connector.getSpatialRefInfo(srid))
        else:
            sr_info = QApplication.translate("DBManagerPlugin", "Undefined")
        if sr_info:
            tbl.append((QApplication.translate("DBManagerPlugin",
                                               "Spatial ref:"),
                        u"{0} ({1})".format(sr_info, srid)))

        # estimated extent
        if not self.table.estimatedExtent:
            # estimated extent information is not displayed yet, so just block
            # table signals to avoid double refreshing
            # (infoViewer->refreshEstimatedExtent->tableChanged->infoViewer)
            self.table.blockSignals(True)
            self.table.refreshTableEstimatedExtent()
            self.table.blockSignals(False)

        if self.table.estimatedExtent:
            estimated_extent_str = (u"{:.9f}, {:.9f} - {:.9f}, "
                                    u"{:.9f}".format(
                                        *self.table.estimatedExtent))

            tbl.append((QApplication.translate("DBManagerPlugin",
                                               "Estimated extent:"),
                        estimated_extent_str))

        # extent
        extent_str = None
        if self.table.extent and len(self.table.extent) == 4:
            extent_str = (u"{:.9f}, {:.9f} - {:.9f}, "
                          u"{:.9f}".format(*self.table.extent))
        elif self.table.rowCount > 0 or self.table.estimatedRowCount > 0:
            # Can't calculate an extent on empty layer
            extent_str = QApplication.translate(
                "DBManagerPlugin",
                '(unknown) (<a href="action:extent/get">find out</a>)')

        if extent_str:
            tbl.append((QApplication.translate("DBManagerPlugin",
                                               "Extent:"), extent_str))

        ret.append(HtmlTable(tbl))

        # Handle extent update metadata
        if (self.table.extent
                and self.table.extent != self.table.estimatedExtent
                and self.table.canUpdateMetadata()):
            ret.append(
                HtmlParagraph(
                    QApplication.translate(
                        "DBManagerPlugin",
                        (u'<warning> Metadata extent is different from'
                         u'real extent. You should <a href="action:extent'
                         u'/update">update it</a>!'))))

        # is there an entry in geometry_columns?
        if self.table.geomType.lower() == 'geometry':
            ret.append(
                HtmlParagraph(
                    QApplication.translate(
                        "DBManagerPlugin",
                        "<warning> There is no entry in geometry_columns!")))

        # find out whether the geometry column has spatial index on it
        if not self.table.isView:
            if not self.table.hasSpatialIndex():
                ret.append(
                    HtmlParagraph(
                        QApplication.translate(
                            "DBManagerPlugin",
                            (u'<warning> No spatial index defined (<a href='
                             u'"action:spatialindex/create">'
                             u'create it</a>).'))))

        return ret
    def testWriteShapefileWithZ(self):
        """Check writing geometries with Z dimension to an ESRI shapefile."""

        # start by saving a memory layer and forcing z
        ml = QgsVectorLayer(('Point?crs=epsg:4326&field=id:int'), 'test',
                            'memory')

        self.assertIsNotNone(ml, 'Provider not initialized')
        self.assertTrue(ml.isValid(), 'Source layer not valid')
        provider = ml.dataProvider()
        self.assertIsNotNone(provider)

        ft = QgsFeature()
        ft.setGeometry(QgsGeometry.fromWkt('PointZ (1 2 3)'))
        ft.setAttributes([1])
        res, features = provider.addFeatures([ft])
        self.assertTrue(res)
        self.assertTrue(features)

        # check with both a standard PointZ and 25d style Point25D type
        for t in [QgsWkbTypes.PointZ, QgsWkbTypes.Point25D]:
            dest_file_name = os.path.join(
                str(QDir.tempPath()),
                'point_{}.shp'.format(QgsWkbTypes.displayString(t)))
            crs = QgsCoordinateReferenceSystem()
            crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId)
            write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat(
                ml,
                dest_file_name,
                'utf-8',
                crs,
                'ESRI Shapefile',
                overrideGeometryType=t)
            self.assertEqual(write_result, QgsVectorFileWriter.NoError,
                             error_message)

            # Open result and check
            created_layer = QgsVectorLayer(
                '{}|layerid=0'.format(dest_file_name), 'test', 'ogr')
            f = next(created_layer.getFeatures(QgsFeatureRequest()))
            g = f.geometry()
            wkt = g.asWkt()
            expWkt = 'PointZ (1 2 3)'
            self.assertTrue(
                compareWkt(expWkt, wkt),
                "saving geometry with Z failed: mismatch Expected:\n%s\nGot:\n%s\n"
                % (expWkt, wkt))

            # also try saving out the shapefile version again, as an extra test
            # this tests that saving a layer with z WITHOUT explicitly telling the writer to keep z values,
            # will stay retain the z values
            dest_file_name = os.path.join(
                str(QDir.tempPath()),
                'point_{}_copy.shp'.format(QgsWkbTypes.displayString(t)))
            crs = QgsCoordinateReferenceSystem()
            crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId)
            write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat(
                created_layer, dest_file_name, 'utf-8', crs, 'ESRI Shapefile')
            self.assertEqual(write_result, QgsVectorFileWriter.NoError,
                             error_message)

            # Open result and check
            created_layer_from_shp = QgsVectorLayer(
                '{}|layerid=0'.format(dest_file_name), 'test', 'ogr')
            f = next(created_layer_from_shp.getFeatures(QgsFeatureRequest()))
            g = f.geometry()
            wkt = g.asWkt()
            self.assertTrue(
                compareWkt(expWkt, wkt),
                "saving geometry with Z failed: mismatch Expected:\n%s\nGot:\n%s\n"
                % (expWkt, wkt))
Example #26
0
        # Pegando o nome da camada
        nome = subLayer.split('!!::!!')[1]
        print('Nome da Camada =', nome)
        uri = f"{full_path}|layername={nome}"
        subCamada = QgsVectorLayer(uri, nome, "ogr")

        # Quantidade de Feições
        qt_feicoes = subCamada.featureCount()
        print(f'Quantidade de feições: {qt_feicoes}')

        # Quantos campos
        qtd_campos = len(subCamada.fields())
        print(f"Quantidade de campos = {qtd_campos}")

        # Tipo de geometria
        tp_geometria = QgsWkbTypes.displayString(subCamada.wkbType())
        print(f"Geometria = {tp_geometria}")

        # SRC
        subSrc = subCamada.crs().authid()
        print(f"SRC = {subSrc}")

        metadado += f"\n\nNome Camada: {nome}"
        metadado += "\nTotal de Feições: {0}".format(qt_feicoes)
        metadado += "\nQuantidade de Campos: %d" % (qtd_campos)
        metadado += f"\nGeometria: {tp_geometria}"
        metadado += f"\nSRC: {subSrc}"
else:
    print('Seu caminho tem algo errado!!!')

nomeMetadado = arquivoFisico.split('.')[0] + "_METADADOS.txt"
    def layerToTTLString(self,
                         layer,
                         urilist=None,
                         classurilist=None,
                         includelist=None,
                         proptypelist=None,
                         valuemappings=None,
                         valuequeries=None):
        fieldnames = [field.name() for field in layer.fields()]
        ttlstring = "<http://www.opengis.net/ont/geosparql#Feature> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Class> .\n"
        ttlstring += "<http://www.opengis.net/ont/geosparql#SpatialObject> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Class> .\n"
        ttlstring += "<http://www.opengis.net/ont/geosparql#Geometry> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Class> .\n"
        ttlstring += "<http://www.opengis.net/ont/geosparql#hasGeometry> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#ObjectProperty> .\n"
        ttlstring += "<http://www.opengis.net/ont/geosparql#asWKT> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#DatatypeProperty> .\n"
        ttlstring += "<http://www.opengis.net/ont/geosparql#Feature> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://www.opengis.net/ont/geosparql#SpatialObject> .\n"
        ttlstring += "<http://www.opengis.net/ont/geosparql#Geometry> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://www.opengis.net/ont/geosparql#SpatialObject> .\n"
        first = 0
        if self.exportNameSpace == None or self.exportNameSpace == "":
            namespace = "http://www.github.com/sparqlunicorn#"
        else:
            namespace = self.exportNameSpace
        if self.exportIdCol == "":
            idcol = "id"
        else:
            idcol = self.exportIdCol
        classcol = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
        curid = ""
        if self.exportSetClass == None or self.exportSetClass == "":
            curclassid = namespace + str(uuid.uuid4())
        elif self.exportSetClass.startswith("http"):
            curclassid = self.exportSetClass
        else:
            curclassid = urllib.parse.quote(self.exportSetClass)
        for f in layer.getFeatures():
            geom = f.geometry()
            if not idcol in fieldnames:
                curid = namespace + str(uuid.uuid4())
            elif not str(f[idcol]).startswith("http"):
                curid = namespace + str(f[idcol])
            else:
                curid = f[idcol]
            if not classcol in fieldnames:
                ttlstring += "<" + str(
                    curid
                ) + "> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <" + curclassid + "> .\n"
                if first == 0:
                    ttlstring += "<" + str(
                        curclassid
                    ) + "> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://www.opengis.net/ont/geosparql#Feature> .\n"
                    ttlstring += "<" + str(
                        curclassid
                    ) + "> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Class> .\n"
            ttlstring += "<" + str(
                curid
            ) + "> <http://www.opengis.net/ont/geosparql#hasGeometry> <" + curid + "_geom> .\n"
            ttlstring += "<" + str(
                curid
            ) + "_geom> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.opengis.net/ont/geosparql#" + QgsWkbTypes.displayString(
                geom.wkbType()) + "> .\n"
            ttlstring += "<http://www.opengis.net/ont/geosparql#" + QgsWkbTypes.displayString(
                geom.wkbType()
            ) + "> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Class> .\n"
            ttlstring += "<http://www.opengis.net/ont/geosparql#" + QgsWkbTypes.displayString(
                geom.wkbType()
            ) + "> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://www.opengis.net/ont/geosparql#Geometry> .\n"
            ttlstring += "<" + str(
                curid
            ) + "_geom> <http://www.opengis.net/ont/geosparql#asWKT> \"" + geom.asWkt(
            ) + "\"^^<http://www.opengis.net/ont/geosparql#wktLiteral> .\n"
            fieldcounter = -1
            for propp in fieldnames:
                fieldcounter += 1
                #if fieldcounter>=len(fieldnames):
                #    fieldcounter=0
                if includelist != None and fieldcounter < len(
                        includelist) and includelist[fieldcounter] == False:
                    continue
                prop = propp
                print(str(fieldcounter))
                print(str(urilist) + "\n")
                print(str(classurilist) + "\n")
                print(str(includelist) + "\n")
                if urilist != None and urilist[fieldcounter] != "":
                    print(urilist)
                    if not urilist[fieldcounter].startswith("http"):
                        print("Does not start with http")
                        prop = urllib.parse.quote(urilist[fieldcounter])
                    else:
                        prop = urilist[fieldcounter]
                    print("New Prop from list: " + str(prop))
                if prop == "id":
                    continue
                if not prop.startswith("http"):
                    prop = namespace + prop
                if prop == "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" and "http" in str(
                        f[propp]):
                    ttlstring += "<" + str(f[propp]) + "> <" + str(
                        prop) + "> <http://www.w3.org/2002/07/owl#Class> .\n"
                    ttlstring += "<" + str(
                        f[propp]
                    ) + "> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://www.opengis.net/ont/geosparql#Feature> .\n"

                #elif urilist!=None and fieldcounter<len(urilist) and urilist[fieldcounter]!="":
                #   ttlstring+="<"+curid+"> <"+prop+"> <"+str(f[propp])+"> .\n"
                #    if first<10:
                #       ttlstring+="<"+prop+"> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#ObjectProperty> .\n"
                #       ttlstring+="<"+prop+"> <http://www.w3.org/2000/01/rdf-schema#domain> <"+curclassid+"> .\n"
                #      if classurilist[fieldcounter]!="":
                #           ttlstring+="<"+prop+"> <http://www.w3.org/2000/01/rdf-schema#range> <"+classurilist[fieldcounter]+"> .\n"
                elif prop == "http://www.w3.org/2000/01/rdf-schema#label" or prop == "http://www.w3.org/2000/01/rdf-schema#comment" or (
                        proptypelist != None and proptypelist[fieldcounter]
                        == "AnnotationProperty"):
                    ttlstring += "<" + curid + "> <" + prop + "> \"" + str(
                        f[propp]).replace(
                            '"', '\\"'
                        ) + "\"^^<http://www.w3.org/2001/XMLSchema#string> .\n"
                    if first < 10:
                        ttlstring += "<" + prop + "> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#AnnotationProperty> .\n"
                        ttlstring += "<" + prop + "> <http://www.w3.org/2000/01/rdf-schema#domain> <" + curclassid + "> .\n"
                elif not f[propp] or f[propp] == None or f[propp] == "":
                    continue
                elif proptypelist != None and proptypelist[
                        fieldcounter] == "SubClass":
                    ttlstring += "<" + curid + "> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <" + str(
                        f[propp]) + "> .\n"
                    ttlstring += "<" + curid + "> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <" + curclassid + "> .\n"
                    if first < 10:
                        ttlstring += "<" + str(
                            f[propp]
                        ) + "> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Class> .\n"
                elif valuequeries != None and propp in valuequeries:
                    ttlstring += ""
                    sparql = SPARQLWrapper(
                        valuequeries[propp][1],
                        agent=
                        "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11"
                    )
                    sparql.setQuery("".join(self.prefixes[endpointIndex]) +
                                    valuequeries[propp][0].replace(
                                        "%%" + propp + "%%", "\"" +
                                        str(f[propp]) + "\""))
                    sparql.setMethod(POST)
                    sparql.setReturnFormat(JSON)
                    results = sparql.query().convert()
                    ttlstring += "<" + curid + "> <" + prop + "> <" + results[
                        "results"]["bindings"][0]["item"]["value"] + "> ."
                    if first < 10:
                        ttlstring += "<" + prop + "> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#ObjectProperty> .\n"
                        ttlstring += "<" + prop + "> <http://www.w3.org/2000/01/rdf-schema#domain> <" + curclassid + "> .\n"
                        if classurilist[fieldcounter] != "":
                            ttlstring += "<" + prop + "> <http://www.w3.org/2000/01/rdf-schema#range> <" + classurilist[
                                fieldcounter] + "> .\n"
                elif valuemappings != None and propp in valuemappings and f[
                        propp] in self.valuemappings[propp]:
                    ttlstring += "<" + curid + "> <" + prop + "> <" + str(
                        self.valuemappings[propp][f[propp]]) + "> .\n"
                    if first < 10:
                        ttlstring += "<" + prop + "> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#ObjectProperty> .\n"
                        ttlstring += "<" + prop + "> <http://www.w3.org/2000/01/rdf-schema#domain> <" + curclassid + "> .\n"
                        if classurilist[fieldcounter] != "":
                            ttlstring += "<" + prop + "> <http://www.w3.org/2000/01/rdf-schema#range> <" + classurilist[
                                fieldcounter] + "> .\n"
                elif "http" in str(f[propp]) or (proptypelist != None
                                                 and proptypelist[fieldcounter]
                                                 == "ObjectProperty"):
                    ttlstring += "<" + curid + "> <" + prop + "> <" + str(
                        f[propp]) + "> .\n"
                    if first < 10:
                        ttlstring += "<" + prop + "> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#ObjectProperty> .\n"
                        ttlstring += "<" + prop + "> <http://www.w3.org/2000/01/rdf-schema#domain> <" + curclassid + "> .\n"
                        if classurilist != None and fieldcounter < len(
                                classurilist
                        ) and classurilist[fieldcounter] != "":
                            ttlstring += "<" + prop + "> <http://www.w3.org/2000/01/rdf-schema#range> <" + classurilist[
                                fieldcounter] + "> .\n"
                elif re.match(r'^-?\d+$', str(f[propp])):
                    ttlstring += "<" + curid + "> <" + prop + "> \"" + str(
                        f[propp]
                    ) + "\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n"
                    if first < 10:
                        ttlstring += "<" + prop + "> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#DatatypeProperty> .\n"
                        ttlstring += "<" + prop + "> <http://www.w3.org/2000/01/rdf-schema#domain> <" + curclassid + "> .\n"
                        ttlstring += "<" + prop + "> <http://www.w3.org/2000/01/rdf-schema#range> <http://www.w3.org/2001/XMLSchema#integer> .\n"
                elif re.match(r'^-?\d+(?:\.\d+)?$', str(f[propp])):
                    ttlstring += "<" + curid + "> <" + prop + "> \"" + str(
                        f[propp]
                    ) + "\"^^<http://www.w3.org/2001/XMLSchema#double> .\n"
                    if first:
                        ttlstring += "<" + prop + "> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#DatatypeProperty> .\n"
                        ttlstring += "<" + prop + "> <http://www.w3.org/2000/01/rdf-schema#domain> <" + curclassid + "> .\n"
                        ttlstring += "<" + prop + "> <http://www.w3.org/2000/01/rdf-schema#range> <http://www.w3.org/2001/XMLSchema#double> .\n"
                else:
                    ttlstring += "<" + curid + "> <" + prop + "> \"" + str(
                        f[propp]).replace(
                            '"', '\\"'
                        ) + "\"^^<http://www.w3.org/2001/XMLSchema#string> .\n"
                    if first < 10:
                        ttlstring += "<" + prop + "> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#DatatypeProperty> .\n"
                        ttlstring += "<" + prop + "> <http://www.w3.org/2000/01/rdf-schema#domain> <" + curclassid + "> .\n"
                        ttlstring += "<" + prop + "> <http://www.w3.org/2000/01/rdf-schema#range> <http://www.w3.org/2001/XMLSchema#string> .\n"
            if first < 10:
                first = first + 1
        return ttlstring
    def testWriteShapefileWithZ(self):
        """Check writing geometries with Z dimension to an ESRI shapefile."""

        # start by saving a memory layer and forcing z
        ml = QgsVectorLayer(
            ('Point?crs=epsg:4326&field=id:int'),
            'test',
            'memory')

        self.assertIsNotNone(ml, 'Provider not initialized')
        self.assertTrue(ml.isValid(), 'Source layer not valid')
        provider = ml.dataProvider()
        self.assertIsNotNone(provider)

        ft = QgsFeature()
        ft.setGeometry(QgsGeometry.fromWkt('PointZ (1 2 3)'))
        ft.setAttributes([1])
        res, features = provider.addFeatures([ft])
        self.assertTrue(res)
        self.assertTrue(features)

        # check with both a standard PointZ and 25d style Point25D type
        for t in [QgsWkbTypes.PointZ, QgsWkbTypes.Point25D]:
            dest_file_name = os.path.join(str(QDir.tempPath()), 'point_{}.shp'.format(QgsWkbTypes.displayString(t)))
            crs = QgsCoordinateReferenceSystem()
            crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId)
            write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat(
                ml,
                dest_file_name,
                'utf-8',
                crs,
                'ESRI Shapefile',
                overrideGeometryType=t)
            self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message)

            # Open result and check
            created_layer = QgsVectorLayer('{}|layerid=0'.format(dest_file_name), 'test', 'ogr')
            f = next(created_layer.getFeatures(QgsFeatureRequest()))
            g = f.geometry()
            wkt = g.asWkt()
            expWkt = 'PointZ (1 2 3)'
            self.assertTrue(compareWkt(expWkt, wkt),
                            "saving geometry with Z failed: mismatch Expected:\n%s\nGot:\n%s\n" % (expWkt, wkt))

            # also try saving out the shapefile version again, as an extra test
            # this tests that saving a layer with z WITHOUT explicitly telling the writer to keep z values,
            # will stay retain the z values
            dest_file_name = os.path.join(str(QDir.tempPath()),
                                          'point_{}_copy.shp'.format(QgsWkbTypes.displayString(t)))
            crs = QgsCoordinateReferenceSystem()
            crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId)
            write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat(
                created_layer,
                dest_file_name,
                'utf-8',
                crs,
                'ESRI Shapefile')
            self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message)

            # Open result and check
            created_layer_from_shp = QgsVectorLayer('{}|layerid=0'.format(dest_file_name), 'test', 'ogr')
            f = next(created_layer_from_shp.getFeatures(QgsFeatureRequest()))
            g = f.geometry()
            wkt = g.asWkt()
            self.assertTrue(compareWkt(expWkt, wkt),
                            "saving geometry with Z failed: mismatch Expected:\n%s\nGot:\n%s\n" % (expWkt, wkt))
    def processAlgorithm(self, parameters, context, feedback):
        # parameters
        # Database connection parameters
        connection_name = QgsExpressionContextUtils.globalScope().variable(
            'gobs_connection_name')

        spatiallayer = self.SPATIALLAYERS[parameters[self.SPATIALLAYER]]
        sourcelayer = self.parameterAsVectorLayer(parameters, self.SOURCELAYER,
                                                  context)
        uniqueid = self.parameterAsString(parameters, self.UNIQUEID, context)
        uniquelabel = self.parameterAsString(parameters, self.UNIQUELABEL,
                                             context)

        msg = ''
        status = 1

        # Get chosen spatial layer id
        id_spatial_layer = spatiallayer.split('-')[-1].strip()
        feedback.pushInfo(
            tr('CHECK COMPATIBILITY BETWEEN SOURCE AND TARGET GEOMETRY TYPES'))
        # Get spatial layer geometry type
        sql = '''
        SELECT sl_geometry_type
        FROM gobs.spatial_layer
        WHERE id = {0}
        LIMIT 1
        '''.format(id_spatial_layer)
        target_type = None
        [header, data, rowCount, ok,
         error_message] = fetchDataFromSqlQuery(connection_name, sql)
        if not ok:
            status = 0
            msg = tr('* The following error has been raised'
                     ) + '  %s' % error_message
            feedback.reportError(msg)
            raise QgsProcessingException(msg)
        else:
            for line in data:
                target_type = line[0].lower()

        # Check multi type
        target_is_multi = target_type.startswith('multi')

        # Get vector layer geometry type
        # And compare it with the spatial_layer type
        source_type = QgsWkbTypes.geometryDisplayString(
            int(sourcelayer.geometryType())).lower()
        source_wtype = QgsWkbTypes.displayString(int(
            sourcelayer.wkbType())).lower()
        ok = True
        if not target_type.endswith(source_type):
            ok = False
            msg = tr(
                'Source vector layer and target spatial layer do not have compatible geometry types'
            )
            msg += ' - SOURCE: {}, TARGET: {}'.format(source_type, target_type)
            feedback.pushInfo(msg)
            raise QgsProcessingException(msg)

        source_is_multi = source_wtype.startswith('multi')

        # Cannot import multi type into single type target spatial layer
        if source_is_multi and not target_is_multi:
            ok = False
            msg = tr(
                'Cannot import a vector layer with multi geometries into a target spatial layer with a simple geometry type defined'
            )
            msg += ' - SOURCE: {}, TARGET: {}'.format(source_wtype,
                                                      target_type)
            feedback.pushInfo(msg)
            raise QgsProcessingException(msg)

        # Import data to temporary table
        feedback.pushInfo(tr('IMPORT SOURCE LAYER INTO TEMPORARY TABLE'))
        temp_schema = 'public'
        temp_table = 'temp_' + str(time.time()).replace('.', '')
        processing.run("qgis:importintopostgis", {
            'INPUT': parameters[self.SOURCELAYER],
            'DATABASE': connection_name,
            'SCHEMA': temp_schema,
            'TABLENAME': temp_table,
            'PRIMARY_KEY': 'gobs_id',
            'GEOMETRY_COLUMN': 'geom',
            'ENCODING': 'UTF-8',
            'OVERWRITE': True,
            'CREATEINDEX': False,
            'LOWERCASE_NAMES': False,
            'DROP_STRING_LENGTH': True,
            'FORCE_SINGLEPART': False
        },
                       context=context,
                       feedback=feedback)
        feedback.pushInfo(
            tr('* Source layer has been imported into temporary table'))
        # Add ST_Multi if needed
        st_multi_left = ''
        st_multi_right = ''
        if target_is_multi:
            st_multi_left = 'ST_Multi('
            st_multi_right = ')'

        # Get target geometry type in integer
        geometry_type_integer = 1
        if target_type.replace('multi', '') == 'linestring':
            geometry_type_integer = 2
        if target_type.replace('multi', '') == 'polygon':
            geometry_type_integer = 3

        # Copy data to spatial_object
        feedback.pushInfo(tr('COPY IMPORTED DATA TO spatial_object'))
        sql = '''
            INSERT INTO gobs.spatial_object
            (so_unique_id, so_unique_label, geom, fk_id_spatial_layer)
            SELECT "{so_unique_id}", "{so_unique_label}", {st_multi_left}ST_Transform(ST_CollectionExtract(ST_MakeValid(geom),{geometry_type_integer}), 4326){st_multi_right} AS geom, {id_spatial_layer}
            FROM "{temp_schema}"."{temp_table}"

            -- Update line if data already exists
            ON CONFLICT ON CONSTRAINT spatial_object_so_unique_id_fk_id_spatial_layer_key
            DO UPDATE
            SET (geom, so_unique_label) = (EXCLUDED.geom, EXCLUDED.so_unique_label)
            WHERE True
            ;
        '''.format(so_unique_id=uniqueid,
                   so_unique_label=uniquelabel,
                   st_multi_left=st_multi_left,
                   geometry_type_integer=geometry_type_integer,
                   st_multi_right=st_multi_right,
                   id_spatial_layer=id_spatial_layer,
                   temp_schema=temp_schema,
                   temp_table=temp_table)
        feedback.pushInfo(sql)
        try:
            [header, data, rowCount, ok,
             error_message] = fetchDataFromSqlQuery(connection_name, sql)
            if not ok:
                status = 0
                msg = tr('* The following error has been raised'
                         ) + '  %s' % error_message
                feedback.reportError(msg)
            else:
                status = 1
                msg = tr('* Source data has been successfully imported !')
                feedback.pushInfo(msg)
        except Exception as e:
            status = 0
            msg = tr(
                '* An unknown error occured while adding features to spatial_object table'
            )
            msg += ' ' + str(e)
        finally:

            # Remove temporary table
            feedback.pushInfo(tr('DROP TEMPORARY DATA'))
            sql = '''
                DROP TABLE IF EXISTS "%s"."%s"
            ;
            ''' % (temp_schema, temp_table)
            [header, data, rowCount, ok,
             error_message] = fetchDataFromSqlQuery(connection_name, sql)
            if ok:
                feedback.pushInfo(tr('* Temporary data has been deleted.'))
            else:
                feedback.reportError(
                    tr('* An error occured while droping temporary table') +
                    ' "%s"."%s"' % (temp_schema, temp_table))

        msg = tr('SPATIAL LAYER HAS BEEN SUCCESSFULLY IMPORTED !')

        return {self.OUTPUT_STATUS: status, self.OUTPUT_STRING: msg}
    def processAlgorithm(self, parameters, context, feedback):
        # parameters
        # Database connection parameters
        connection_name = QgsExpressionContextUtils.projectScope(
            context.project()).variable('gobs_connection_name')
        if not connection_name:
            connection_name = os.environ.get("GOBS_CONNECTION_NAME")

        spatiallayer = self.SPATIALLAYERS[parameters[self.SPATIALLAYER]]
        sourcelayer = self.parameterAsVectorLayer(parameters, self.SOURCELAYER,
                                                  context)
        uniqueid = self.parameterAsString(parameters, self.UNIQUEID, context)
        uniquelabel = self.parameterAsString(parameters, self.UNIQUELABEL,
                                             context)
        date_validity_min = self.parameterAsString(parameters,
                                                   self.DATE_VALIDITY_MIN,
                                                   context)
        manual_date_validity_min = self.parameterAsString(
            parameters, self.MANUAL_DATE_VALIDITY_MIN, context)
        date_validity_max = self.parameterAsString(parameters,
                                                   self.DATE_VALIDITY_MAX,
                                                   context)
        manual_date_validity_max = self.parameterAsString(
            parameters, self.MANUAL_DATE_VALIDITY_MAX, context)

        msg = ''
        status = 1

        # Get chosen spatial layer id
        id_spatial_layer = spatiallayer.split('-')[-1].strip()
        feedback.pushInfo(
            tr('CHECK COMPATIBILITY BETWEEN SOURCE AND TARGET GEOMETRY TYPES'))
        # Get spatial layer geometry type
        sql = '''
        SELECT sl_geometry_type
        FROM gobs.spatial_layer
        WHERE id = {0}
        LIMIT 1
        '''.format(id_spatial_layer)
        target_type = None
        [header, data, rowCount, ok,
         error_message] = fetchDataFromSqlQuery(connection_name, sql)
        if not ok:
            status = 0
            msg = tr('* The following error has been raised'
                     ) + '  %s' % error_message
            feedback.reportError(msg)
            raise QgsProcessingException(msg)
        else:
            for line in data:
                target_type = line[0].lower()

        # Check multi type
        target_is_multi = target_type.startswith('multi')

        # Get vector layer geometry type
        # And compare it with the spatial_layer type
        source_type = QgsWkbTypes.geometryDisplayString(
            int(sourcelayer.geometryType())).lower()
        source_wtype = QgsWkbTypes.displayString(int(
            sourcelayer.wkbType())).lower()
        ok = True
        if not target_type.endswith(source_type):
            ok = False
            msg = tr(
                'Source vector layer and target spatial layer do not have compatible geometry types'
            )
            msg += ' - SOURCE: {}, TARGET: {}'.format(source_type, target_type)
            feedback.pushInfo(msg)
            raise QgsProcessingException(msg)

        source_is_multi = source_wtype.startswith('multi')

        # Cannot import multi type into single type target spatial layer
        if source_is_multi and not target_is_multi:
            ok = False
            msg = tr(
                'Cannot import a vector layer with multi geometries into a target spatial layer with a simple geometry type defined'
            )
            msg += ' - SOURCE: {}, TARGET: {}'.format(source_wtype,
                                                      target_type)
            feedback.pushInfo(msg)
            raise QgsProcessingException(msg)

        # Import data to temporary table
        feedback.pushInfo(tr('IMPORT SOURCE LAYER INTO TEMPORARY TABLE'))
        temp_schema = 'public'
        temp_table = 'temp_' + str(time.time()).replace('.', '')
        processing.run("qgis:importintopostgis", {
            'INPUT': parameters[self.SOURCELAYER],
            'DATABASE': connection_name,
            'SCHEMA': temp_schema,
            'TABLENAME': temp_table,
            'PRIMARY_KEY': 'gobs_id',
            'GEOMETRY_COLUMN': 'geom',
            'ENCODING': 'UTF-8',
            'OVERWRITE': True,
            'CREATEINDEX': False,
            'LOWERCASE_NAMES': False,
            'DROP_STRING_LENGTH': True,
            'FORCE_SINGLEPART': False
        },
                       context=context,
                       feedback=feedback)
        feedback.pushInfo(
            tr('* Source layer has been imported into temporary table'))
        # Add ST_Multi if needed
        st_multi_left = ''
        st_multi_right = ''
        if target_is_multi:
            st_multi_left = 'ST_Multi('
            st_multi_right = ')'

        # Get target geometry type in integer
        geometry_type_integer = 1
        if target_type.replace('multi', '') == 'linestring':
            geometry_type_integer = 2
        if target_type.replace('multi', '') == 'polygon':
            geometry_type_integer = 3

        # Format validity timestamp fields
        if manual_date_validity_min.strip():
            manualdate = manual_date_validity_min.strip().replace('/', '-')
            casted_timestamp_min = '''
                '{0}'::timestamp
            '''.format(manualdate)
        else:
            casted_timestamp_min = '''
                s."{0}"::timestamp
            '''.format(date_validity_min)

        has_max_validity = False
        if manual_date_validity_max.strip() or date_validity_max:
            has_max_validity = True
            if manual_date_validity_max.strip():
                manualdate = manual_date_validity_max.strip().replace('/', '-')
                casted_timestamp_max = '''
                    '{0}'::timestamp
                '''.format(manualdate)
            else:
                casted_timestamp_max = '''
                    s."{0}"::timestamp
                '''.format(date_validity_max)

        # Copy data to spatial_object
        feedback.pushInfo(tr('COPY IMPORTED DATA TO spatial_object'))
        sql = '''
            INSERT INTO gobs.spatial_object (
                so_unique_id, so_unique_label,
                geom, fk_id_spatial_layer,
                so_valid_from
            '''
        if has_max_validity:
            sql += ', so_valid_to'
        sql += '''
            )
            SELECT "{so_unique_id}", "{so_unique_label}", {st_multi_left}ST_Transform(ST_CollectionExtract(ST_MakeValid(geom),{geometry_type_integer}), 4326){st_multi_right} AS geom, {id_spatial_layer},
            {casted_timestamp_min}
        '''.format(so_unique_id=uniqueid,
                   so_unique_label=uniquelabel,
                   st_multi_left=st_multi_left,
                   geometry_type_integer=geometry_type_integer,
                   st_multi_right=st_multi_right,
                   id_spatial_layer=id_spatial_layer,
                   casted_timestamp_min=casted_timestamp_min)
        if has_max_validity:
            sql += ', {casted_timestamp_max}'.format(
                casted_timestamp_max=casted_timestamp_max)
        sql += '''
            FROM "{temp_schema}"."{temp_table}" AS s

            -- Update line if data already exists
            -- i.e. Same external ids for the same layer and the same start validity date
            -- so_unique_id, fk_id_spatial_layer AND so_valid_from are the same
            -- This is considered as the same object as the one already in database
            -- We update the geometry, label, and end date of validity
            ON CONFLICT
                ON CONSTRAINT spatial_object_unique_key
            DO UPDATE
            SET (geom, so_unique_label, so_valid_to) = (EXCLUDED.geom, EXCLUDED.so_unique_label, EXCLUDED.so_valid_to)
            WHERE True
            ;

        '''.format(temp_schema=temp_schema, temp_table=temp_table)

        try:
            [header, data, rowCount, ok,
             error_message] = fetchDataFromSqlQuery(connection_name, sql)
            if not ok:
                status = 0
                msg = tr('* The following error has been raised'
                         ) + '  %s' % error_message
                feedback.reportError(msg)
                feedback.pushInfo(sql)
            else:
                status = 1
                msg = tr('* Source data has been successfully imported !')
                feedback.pushInfo(msg)
        except Exception as e:
            status = 0
            msg = tr(
                '* An unknown error occured while adding features to spatial_object table'
            )
            msg += ' ' + str(e)

        # Check there is no issues with related observation data
        # For each series related to the chosen spatial layer
        # SELECT gobs.find_observation_with_wrong_spatial_object({fk_id_series})
        # v1/ Only check and display warning
        # v2/ Check and try to update with gobs.update_observations_with_wrong_spatial_objects
        # v3/ Find orphans

        # Remove temporary table
        feedback.pushInfo(tr('DROP TEMPORARY DATA'))
        sql = '''
            DROP TABLE IF EXISTS "%s"."%s"
        ;
        ''' % (temp_schema, temp_table)
        [header, data, rowCount, ok,
         error_message] = fetchDataFromSqlQuery(connection_name, sql)
        if ok:
            feedback.pushInfo(tr('* Temporary data has been deleted.'))
        else:
            feedback.reportError(
                tr('* An error occured while droping temporary table') +
                ' "%s"."%s"' % (temp_schema, temp_table))

        msg = tr('SPATIAL LAYER HAS BEEN SUCCESSFULLY IMPORTED !')

        return {self.OUTPUT_STATUS: status, self.OUTPUT_STRING: msg}
Example #31
0
        nome = subLayer.split("!!::!!")[1]
        print("Nome da layer =", nome)
        uri = "%s|layername=%s" % (
            full_path, nome
        )  # Se o python for 3.6 + pode-se usar f"{full_path}|layername={nome}"
        # Cria Camada
        sub_vlayer = QgsVectorLayer(uri, nome, 'ogr')
        # quantas feicoes
        print("Total de feições =", sub_vlayer.featureCount())

        # Quantidade de Campos
        qtd_campos = len(sub_vlayer.fields())
        print("Quantidade de campos =", qtd_campos)

        # qual geometria
        geometria = QgsWkbTypes.displayString(sub_vlayer.wkbType())
        print("Geometria =", geometria)

        # como pegar geometria
        print(sub_vlayer.wkbType())
        # consulta crs
        print("SRC =", sub_vlayer.crs().authid(), "\n\n")

        # Montando Metadado
        metadado += f"""\n\nCamada = {nome}"""
        metadado += f"""\nTotal de feições = {sub_vlayer.featureCount()}"""
        metadado += f"""\nQuantidade de campos = {qtd_campos}"""
        metadado += f"""\nGeometria = {geometria}"""
        metadado += f"""\nSRC = {sub_vlayer.crs().authid()}"""
else:
    print("nao deu")
Example #32
0
    def write_csv(self, out_directory):

        msg = f"writing csv..."
        logger.debug(msg)
        QgsMessageLog.logMessage(msg, "fmsf2hms")
        start = datetime.now()

        def parse_datestring(value, siteid):

            clean = ''.join(n for n in value
                            if n.isdigit() or n in ['-', '/', '\\'])
            clean = clean.rstrip("-")
            if clean.rstrip() == "":
                return ""
            if len(clean) == 4:
                return "{}-01-01".format(clean)
            elif len(clean) > 4:
                try:
                    d = parse(clean)
                    return d.strftime("%Y-%m-%d")
                except Exception as e:
                    msg = f"Unexpected date value (1) in {siteid}: {clean}"
                    logger.debug(msg)
                    logger.debug(e)
                    QgsMessageLog.logMessage(msg, "fmsf2hms")
                    QgsMessageLog.logMessage(e, "fmsf2hms")
                    return ""
            else:
                msg = f"Unexpected date value (2) in {siteid}: {clean}"
                logger.debug(msg)
                QgsMessageLog.logMessage(msg, "fmsf2hms")
                return ""

        def sanitize_attributes(attributes, fields):

            field_info = {i.name(): i.typeName() for i in fields}

            siteid = attributes[self.siteid_index]
            row = list()
            fields_to_concat = []
            concat_vals = {}
            for k, v in self.configs['concat_fields'].items():
                concat_vals[k] = []
                fields_to_concat += v
            for index, attr in enumerate(attributes):
                fname = list(field_info.keys())[index]
                if str(attr) == "NULL":
                    value = ""
                else:
                    value = str(attr)
                    if value == "Unspecified by surveyor":
                        value = "Unspecified by Surveyor"

                if fname in self.configs['date_fields']:
                    if field_info[fname] == "date" and value != "":
                        value = attr.toString("yyyy-MM-dd")
                    else:
                        value = parse_datestring(value, siteid)

                if fname not in fields_to_concat:
                    row.append(value)
                    continue

                for k, v in self.configs['concat_fields'].items():
                    if fname in v and not value == "":
                        concat_vals[k].append(value)

            new_concat = list(self.configs['concat_fields'].keys())
            new_concat.sort()
            for nc in new_concat:
                trans_cat = list()
                for i in concat_vals[nc]:
                    if "," in i:
                        trans_cat.append(f'"{i}"')
                    else:
                        trans_cat.append(i)
                row.append(",".join(trans_cat))
            return row

        field_names = self.in_layer.fields().names()
        fields = ['ResourceID', 'geom'] + field_names
        concat_fields = list()
        for new, orig in self.configs['concat_fields'].items():
            concat_fields.append(new)
            fields = [i for i in fields if i not in orig]

        concat_fields.sort()
        fields += concat_fields

        out_path = os.path.join(out_directory, self.configs['out_file_name'])
        with open(out_path, "w", newline="") as outcsv:
            writer = csv.writer(outcsv)
            writer.writerow(fields)
            for feature in self.in_layer.getFeatures():
                id = str(uuid.uuid4())
                wkt_geom = feature.geometry().asWkt(precision=9)
                featrow = sanitize_attributes(feature.attributes(),
                                              self.in_layer.fields())
                outrow = [id, wkt_geom] + featrow
                writer.writerow(outrow)

        g = QgsWkbTypes.displayString(self.in_layer.wkbType())
        geoms = {
            "Point": "point",
            "MultiPoint": "point",
            "Polygon": "polygon",
            "MultiPolygon": "polygon",
        }

        load_uri = "file:///" + out_path + "?type=csv&wktField=geom&crs=EPSG:4326&geomType=" + geoms[
            g]
        csv_layer = QgsVectorLayer(load_uri, self.configs['layer_name'],
                                   "delimitedtext")
        QgsProject.instance().addMapLayer(csv_layer)

        msg = f"  - done in {datetime.now() - start}."
        logger.debug(msg)
        QgsMessageLog.logMessage(msg, "fmsf2hms")

        return os.path.abspath(out_path)
Example #33
0
    def run(self):
        try:
            # Check if the layers look OK
            if self.inpvl is None or self.joinvl is None:
                self.status.emit('Layer is missing!')
                self.finished.emit(False, None)
                return
            # Check if there are features in the layers
            incount = 0
            if self.selectedinonly:
                incount = self.inpvl.selectedFeatureCount()
            else:
                incount = self.inpvl.featureCount()
            if incount == 0:
                self.status.emit('Input layer has no features!')
                self.finished.emit(False, None)
                return
            joincount = 0
            if self.selectedjoonly:
                joincount = self.joinvl.selectedFeatureCount()
            else:
                joincount = self.joinvl.featureCount()
            if joincount == 0:
                self.status.emit('Join layer has no features!')
                self.finished.emit(False, None)
                return
            # Get the wkbtype of the layers
            self.inpWkbType = self.inpvl.wkbType()
            self.joinWkbType = self.joinvl.wkbType()

            # Check if the input layer does not have geometries
            if (self.inpvl.geometryType() == QgsWkbTypes.NullGeometry):
                self.status.emit('No geometries in the input layer!')
                self.finished.emit(False, None)
                return
            # Check if the join layer does not have geometries
            if (self.joinvl.geometryType() == QgsWkbTypes.NullGeometry):
                self.status.emit('No geometries in the join layer!')
                self.finished.emit(False, None)
                return
            # Set the geometry type and prepare the output layer
            inpWkbTypetext = QgsWkbTypes.displayString(int(self.inpWkbType))
            # self.inputmulti = QgsWkbTypes.isMultiType(self.inpWkbType)
            # self.status.emit('wkbtype: ' + inpWkbTypetext)
            # geometryType = self.inpvl.geometryType()
            # geometrytypetext = 'Point'
            # if geometryType == QgsWkbTypes.PointGeometry:
            #     geometrytypetext = 'Point'
            # elif geometryType == QgsWkbTypes.LineGeometry:
            #     geometrytypetext = 'LineString'
            # elif geometryType == QgsWkbTypes.PolygonGeometry:
            #     geometrytypetext = 'Polygon'
            # if self.inputmulti:
            #     geometrytypetext = 'Multi' + geometrytypetext
            # geomttext = geometrytypetext

            geomttext = inpWkbTypetext
            # Set the coordinate reference system to the input
            # layer's CRS using authid (proj4 may be more robust)
            if self.inpvl.crs() is not None:
                geomttext = (geomttext + "?crs=" +
                             str(self.inpvl.crs().authid()))
            # Retrieve the fields from the input layer
            outfields = self.inpvl.fields().toList()
            # Retrieve the fields from the join layer
            if self.joinvl.fields() is not None:
                jfields = self.joinvl.fields().toList()
                for joinfield in jfields:
                    outfields.append(
                        QgsField(self.joinprefix + str(joinfield.name()),
                                 joinfield.type()))
            else:
                self.status.emit('Unable to get any join layer fields')
            # Add the nearest neighbour distance field
            # Check if there is already a "distance" field
            # (should be avoided in the user interface)
            # Try a new name if there is a collission
            collission = True
            trynumber = 1
            distnameorg = self.distancename
            while collission:  # Iterate until there are no collissions
                collission = False
                for field in outfields:
                    # This check should not be necessary - handled in the UI
                    if field.name() == self.distancename:
                        self.status.emit(
                            'Distance field already exists - renaming!')
                        # self.abort = True
                        # self.finished.emit(False, None)
                        # break
                        collission = True
                        self.distancename = distnameorg + str(trynumber)
                        trynumber = trynumber + 1
            outfields.append(QgsField(self.distancename, QVariant.Double))
            # Create a memory layer using a CRS description
            self.mem_joinl = QgsVectorLayer(geomttext, self.outputlayername,
                                            "memory")
            # Set the CRS to the inputlayer's CRS
            self.mem_joinl.setCrs(self.inpvl.crs())
            self.mem_joinl.startEditing()
            # Add the fields
            for field in outfields:
                self.mem_joinl.dataProvider().addAttributes([field])
            # For an index to be used, the input layer has to be a
            # point layer, or the input layer geometries have to be
            # approximated to centroids, or the user has to have
            # accepted that a join layer index is used (for
            # non-point input layers).
            # (Could be extended to multipoint)
            if (self.inpWkbType == QgsWkbTypes.Point
                    or self.inpWkbType == QgsWkbTypes.Point25D
                    or self.approximateinputgeom or self.nonpointexactindex):
                # Number of features in the join layer - used by
                # calculate_progress for the index creation
                if self.selectedjoonly:
                    self.feature_count = self.joinvl.selectedFeatureCount()
                else:
                    self.feature_count = self.joinvl.featureCount()
                # Create a spatial index to speed up joining
                self.status.emit('Creating join layer index...')
                # The number of elements that is needed to increment the
                # progressbar - set early in run()
                self.increment = self.feature_count // 1000
                self.joinlind = QgsSpatialIndex()
                # Include geometries to enable exact distance calculations
                # self.joinlind = QgsSpatialIndex(flags=[QgsSpatialIndex.FlagStoreFeatureGeometries])

                if self.selectedjoonly:
                    for feat in self.joinvl.getSelectedFeatures():
                        # Allow user abort
                        if self.abort is True:
                            break
                        self.joinlind.insertFeature(feat)
                        self.calculate_progress()
                else:
                    for feat in self.joinvl.getFeatures():
                        # Allow user abort
                        if self.abort is True:
                            break
                        self.joinlind.insertFeature(feat)
                        self.calculate_progress()
                self.status.emit('Join layer index created!')
                self.processed = 0
                self.percentage = 0
                # self.calculate_progress()

            # Is the join layer a multi-geometry layer?
            # self.joinmulti = QgsWkbTypes.isMultiType(self.joinWkbType)
            # Does the join layer contain multi geometries?
            # Try to check the first feature
            # This is not used for anything yet
            self.joinmulti = False
            if self.selectedjoonly:
                feats = self.joinvl.getSelectedFeatures()
            else:
                feats = self.joinvl.getFeatures()
            if feats is not None:
                testfeature = next(feats)
                feats.rewind()
                feats.close()
                if testfeature is not None:
                    if testfeature.hasGeometry():
                        if testfeature.geometry().isMultipart():
                            self.joinmulti = True
            # Prepare for the join by fetching the layers into memory
            # Add the input features to a list
            self.inputf = []
            if self.selectedinonly:
                for f in self.inpvl.getSelectedFeatures():
                    self.inputf.append(f)
            else:
                for f in self.inpvl.getFeatures():
                    self.inputf.append(f)
            # Add the join features to a list (used in the join)
            self.joinf = []
            if self.selectedjoonly:
                for f in self.joinvl.getSelectedFeatures():
                    self.joinf.append(f)
            else:
                for f in self.joinvl.getFeatures():
                    self.joinf.append(f)
            # Initialise the global variable that will contain the
            # result of the nearest neighbour spatial join (list of
            # features)
            self.features = []
            # Do the join!
            # Number of features in the input layer - used by
            # calculate_progress for the join operation
            if self.selectedinonly:
                self.feature_count = self.inpvl.selectedFeatureCount()
            else:
                self.feature_count = self.inpvl.featureCount()
            # The number of elements that is needed to increment the
            # progressbar - set early in run()
            self.increment = self.feature_count // 1000
            # Using the original features from the input layer
            for feat in self.inputf:
                # Allow user abort
                if self.abort is True:
                    break
                self.do_indexjoin(feat)
                self.calculate_progress()
            self.mem_joinl.dataProvider().addFeatures(self.features)
            self.status.emit('Join finished')
        except:
            import traceback
            self.error.emit(traceback.format_exc())
            self.finished.emit(False, None)
            if self.mem_joinl is not None:
                self.mem_joinl.rollBack()
        else:
            self.mem_joinl.commitChanges()
            if self.abort:
                self.finished.emit(False, None)
            else:
                self.status.emit('Delivering the memory layer...')
                self.finished.emit(True, self.mem_joinl)
    def cloneToMemory(self):
        curlayer = self.iface.mapCanvas().currentLayer()
        selectedFeatCount = curlayer.selectedFeatureCount()
        geo = QgsWkbTypes.displayString(
            curlayer.wkbType())  # wkbType string name of geometry

        targetLayer = QgsVectorLayer(geo, self.dlg.lineEdit_2.text(), "memory")
        targetLayer.setCrs(curlayer.sourceCrs())
        QgsProject.instance().addMapLayer(targetLayer, False)
        root = QgsProject.instance().layerTreeRoot()

        self.setStyleLayer(targetLayer)

        if self.dlg.checkBoxAtrib.isChecked():  #copy attributes
            curlayer_attribute_list = curlayer.fields().toList()
            targetLayer_attribute_list = []
            targetLayerpr = targetLayer.dataProvider()

            for attrib in curlayer_attribute_list:
                if targetLayer.fields().lookupField(attrib.name()) == -1:
                    targetLayer_attribute_list.append(
                        QgsField(attrib.name(), attrib.type()))
            with edit(targetLayer):
                for attr in targetLayer_attribute_list:
                    if attr.type(
                    ) == 1:  # иначе игнорируется поле с типом 1 (bool)
                        attr = QgsField(
                            attr.name(),
                            QVariant.String)  # конвертируем bool в string
                    res_add = targetLayer.addAttribute(attr)
                    if not res_add:
                        print(u'Не создано поле {}'.format(attr.name()))
            targetLayer.updateFields()

        # for feat in curlayer.selectedFeatures(): # not work more
        #     targetLayer.dataProvider().addFeatures([feat]) # not work more

        # ИЗ МОДУЛЯ Apend Features To layer -----------------------------------------------
        # В старом варианте в QGIS3 при добавлении объектов с отличающимся набором аттрибутов
        # происходила задержка с выводом сообщений в логи. Что затягивало процесс.
        mapping = dict()
        for target_idx in targetLayer.fields().allAttributesList():
            target_field = targetLayer.fields().field(target_idx)
            source_idx = curlayer.fields().indexOf(target_field.name())
            if source_idx != -1:
                mapping[target_idx] = source_idx

        features = curlayer.selectedFeatures()
        destType = targetLayer.geometryType()
        destIsMulti = QgsWkbTypes.isMultiType(targetLayer.wkbType())
        new_features = []

        for current, in_feature in enumerate(features):
            attrs = {
                target_idx: in_feature[source_idx]
                for target_idx, source_idx in mapping.items()
            }
            geom = QgsGeometry()
            if in_feature.hasGeometry() and targetLayer.isSpatial():
                # Convert geometry to match destination layer
                # Adapted from QGIS qgisapp.cpp, pasteFromClipboard()
                geom = in_feature.geometry()
                if destType != QgsWkbTypes.UnknownGeometry:
                    newGeometry = geom.convertToType(destType, destIsMulti)
                    if newGeometry.isNull():
                        continue
                    geom = newGeometry
                # Avoid intersection if enabled in digitize settings
                geom.avoidIntersections(
                    QgsProject.instance().avoidIntersectionsLayers())

            new_feature = QgsVectorLayerUtils().createFeature(
                targetLayer, geom, attrs)
            new_features.append(new_feature)

        with edit(targetLayer):
            res = targetLayer.addFeatures(new_features)
        # ИЗ МОДУЛЯ Apend Features To layer -----------------------------------------------end

        root.insertLayer(0, targetLayer)
        self.iface.messageBar().clearWidgets()
        self.iface.setActiveLayer(targetLayer)
        curlayer.selectByIds([])

        if res:
            self.iface.messageBar().pushMessage(
                u"Выполнено",
                u"Склонировано {0}/{1} объектов".format(
                    len(new_features), selectedFeatCount),
                duration=5,
                level=0)
Example #35
0
    def response_data_mode(self, request, export_features=False):
        """
        Query layer and return data
        :param request: DjangoREST API request object
        :param formatter: Boolean, default False, True for to use QgsJsonExport.exportFeatures method
        :return: response dict data
        """

        # Create the QGIS feature request, it will be passed through filters
        # and to the final QGIS API get features call.
        qgis_feature_request = QgsFeatureRequest()

        # Prepare arguments for the get feature call
        kwargs = {}

        # Apply filter backends, store original subset string
        original_subset_string = self.metadata_layer.qgis_layer.subsetString()
        if hasattr(self, 'filter_backends'):
            for backend in self.filter_backends:
                backend().apply_filter(request, self.metadata_layer.qgis_layer, qgis_feature_request, self)

        # Paging cannot be a backend filter
        if 'page' in request.query_params:
            kwargs['page'] = request.query_params.get('page')
            kwargs['page_size'] = request.query_params.get('page_size', 10)

        self.features = get_qgis_features(
            self.metadata_layer.qgis_layer, qgis_feature_request, **kwargs)
        ex = QgsJsonExporter(self.metadata_layer.qgis_layer)

        # If 'unique' request params is set,
        # api return a list of unique
        # field name sent with 'unique' param.
        # --------------------------------------
        # IDEA:     for big data it'll be iterate over features to get unique
        #           c++ iteration is fast. Instead memory layer fith to much features can be a problem.
        if 'unique' in request.query_params:

            vl = QgsVectorLayer(QgsWkbTypes.displayString(self.metadata_layer.qgis_layer.wkbType()),
                                "temporary_vector", "memory")
            pr = vl.dataProvider()

            # add fields
            pr.addAttributes(self.metadata_layer.qgis_layer.fields())
            vl.updateFields()  # tell the vector layer to fetch changes from the provider

            res = pr.addFeatures(self.features)

            uniques = vl.uniqueValues(
                self.metadata_layer.qgis_layer.fields().indexOf(request.query_params.get('unique'))
            )

            values = []
            for u in uniques:
                try:
                    if u:
                        values.append(json.loads(QgsJsonUtils.encodeValue(u)))
                except Exception as e:
                    logger.error(f'Response vector widget unique: {e}')
                    continue

            self.results.update({
                'data': values,
                'count': len(values)
            })

            del(vl)

        else:

            # patch for return GeoJson feature with CRS different from WGS84
            # TODO: use .setTransformGeometries( false ) with QGIS >= 3.12
            ex.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:4326'))

            # check for formatter query url param and check if != 0
            if 'formatter' in request.query_params:
                formatter = request.query_params.get('formatter')
                if formatter.isnumeric() and int(formatter) == 0:
                    export_features = False
                else:
                    export_features = True

            if export_features:
                feature_collection = json.loads(ex.exportFeatures(self.features))
            else:

                # to exclude QgsFormater used into QgsJsonjExporter is necessary build by hand single json feature
                ex.setIncludeAttributes(False)

                feature_collection = {
                    'type': 'FeatureCollection',
                    'features': []
                }

                for feature in self.features:
                    fnames = [f.name() for f in feature.fields()]
                    feature_collection['features'].append(
                        json.loads(ex.exportFeature(feature, dict(zip(fnames, feature.attributes()))))
                    )



            # FIXME: QGIS api reprojecting?
            # Reproject if necessary
            # if self.reproject:
            #    self.reproject_featurecollection(feature_collection)

            # Change media
            self.change_media(feature_collection)

            self.results.update(APIVectorLayerStructure(**{
                'data': feature_collection,
                'count': count_qgis_features(self.metadata_layer.qgis_layer, qgis_feature_request, **kwargs),
                'geometryType': self.metadata_layer.geometry_type,
            }).as_dict())

            # FIXME: add extra fields data by signals and receivers
            # FIXME: featurecollection = post_serialize_maplayer.send(layer_serializer, layer=self.layer_name)
            # FIXME: Not sure how to map this to the new QGIS API

        # Restore the original subset string
        self.metadata_layer.qgis_layer.setSubsetString(original_subset_string)
Example #36
0
def feature_validator(feature, layer):
    """Validate a QGIS feature by checking QGIS fields constraints

    The logic here is to:
    - if geometry is not None check if geometry type matches the layer type
    - loop through the fields and check for constraints:
        - NOT NULL, skip the next check if this fails
        - UNIQUE (only if not NULL)
        - EXPRESSION (QgsExpression configured in the form), always evaluated,
          even in case of NULLs

    Note: only hard constraints are checked!

    :param feature: QGIS feature
    :type feature: QgsFeature
    :param layer: QGIS layer
    :type layer: QgsVectorLayer
    :return: a dictionary of errors for each field + geometry
    :rtype: dict
    """

    errors = dict()
    geometry = feature.geometry()

    data_provider = layer.dataProvider()

    def _has_default_value(field_index, field):
        return (
            # Provider level
            data_provider.defaultValueClause(field_index)
            or data_provider.defaultValue(field_index)
            or field.defaultValueDefinition().isValid())

    # Check geometry type
    if not geometry.isNull() and geometry.wkbType() != layer.wkbType():
        if not (geometry.wkbType() == QgsWkbTypes.Point25D
                and layer.wkbType() == QgsWkbTypes.PointZ
                or geometry.wkbType() == QgsWkbTypes.Polygon25D
                and layer.wkbType() == QgsWkbTypes.PolygonZ
                or geometry.wkbType() == QgsWkbTypes.LineString25D
                and layer.wkbType() == QgsWkbTypes.LineStringZ
                or geometry.wkbType() == QgsWkbTypes.MultiPoint25D
                and layer.wkbType() == QgsWkbTypes.MultiPointZ
                or geometry.wkbType() == QgsWkbTypes.MultiPolygon25D
                and layer.wkbType() == QgsWkbTypes.MultiPolygonZ
                or geometry.wkbType() == QgsWkbTypes.MultiLineString25D
                and layer.wkbType() == QgsWkbTypes.MultiLineStringZ):

            errors['geometry'] = _(
                'Feature geometry type %s does not match layer type: %s') % (
                    QgsWkbTypes.displayString(geometry.wkbType()),
                    QgsWkbTypes.displayString(layer.wkbType()))

    def _set_error(field_name, error):
        if not field_name in errors:
            errors[field_name] = []
        errors[field_name].append(error)

    # Check fields "hard" constraints
    for field_index in range(layer.fields().count()):

        field = layer.fields().field(field_index)

        # check if fields is a join field:
        if layer.fields().fieldOrigin(field_index) == QgsFields.OriginJoin:
            continue

        # Check not null first, if it fails skip other tests (unique and expression)
        value = feature.attribute(field.name())
        # If there is a default value we assume it's not NULL (we cannot really know at this point
        # what will be the result of the default value clause evaluation, it might even be provider-side
        if (value is None or value
                == QVariant()) and not _has_default_value(field_index, field):
            not_null = (field.constraints().constraintOrigin(
                QgsFieldConstraints.ConstraintNotNull) !=
                        QgsFieldConstraints.ConstraintOriginNotSet
                        and field.constraints().constraintStrength(
                            QgsFieldConstraints.ConstraintNotNull)
                        == QgsFieldConstraints.ConstraintStrengthHard)
            if not_null:
                _set_error(field.name(), _('Field value must be NOT NULL'))
                continue

        value = feature.attribute(field_index)

        # Skip if NULL, not sure if we want to continue in this case but it seems pointless
        # to check for unique or type compatibility on NULLs
        if value is not None and value != QVariant():

            if not QVariant(value).convert(field.type()):
                _set_error(
                    field.name(),
                    _('Field value \'%s\' cannot be converted to %s') %
                    (value, QVariant.typeToName(field.type())))

            unique = (field.constraints().constraintOrigin(
                QgsFieldConstraints.ConstraintUnique) !=
                      QgsFieldConstraints.ConstraintOriginNotSet
                      and field.constraints().constraintStrength(
                          QgsFieldConstraints.ConstraintUnique)
                      == QgsFieldConstraints.ConstraintStrengthHard)

            if unique:
                # Search for features, excluding self if it's an update
                request = QgsFeatureRequest()
                request.setNoAttributes()
                request.setFlags(QgsFeatureRequest.NoGeometry)
                request.setLimit(2)
                if field.isNumeric():
                    request.setFilterExpression(
                        '"%s" = %s' %
                        (field.name().replace('"', '\\"'), value))
                elif field.type() == QVariant.String:
                    request.setFilterExpression(
                        '"%s" = \'%s\'' % (field.name().replace(
                            '"', '\\"'), value.replace("'", "\\'")))
                elif field.type() == QVariant.Date:
                    request.setFilterExpression(
                        'to_date("%s") = \'%s\'' % (field.name().replace(
                            '"', '\\"'), value.toString(Qt.ISODate)))
                elif field.type() == QVariant.DateTime:
                    request.setFilterExpression(
                        'to_datetime("{field_name}") = \'{date_time_string}\' OR to_datetime("{field_name}") = \'{date_time_string}.000\''
                        .format(field_name=field.name().replace('"', '\\"'),
                                date_time_string=value.toString(Qt.ISODate)))
                elif field.type(
                ) == QVariant.Bool:  # This does not make any sense, but still
                    request.setFilterExpression(
                        '"%s" = %s' % (field.name().replace(
                            '"', '\\"'), 'true' if value else 'false'))
                else:  # All the other formats: let's convert to string and hope for the best
                    request.setFilterExpression(
                        '"%s" = \'%s\'' %
                        (field.name().replace('"', '\\"'), value.toString()))

                # Exclude same feature by id
                found = [
                    f.id() for f in layer.getFeatures(request)
                    if f.id() != feature.id()
                ]
                if len(found) > 0:
                    _set_error(field.name(), _('Field value must be UNIQUE'))

        # Check for expressions, even in case of NULL because expressions may want to check for combined
        # conditions on multiple fields
        expression = (field.constraints().constraintOrigin(
            QgsFieldConstraints.ConstraintExpression) !=
                      QgsFieldConstraints.ConstraintOriginNotSet
                      and field.constraints().constraintStrength(
                          QgsFieldConstraints.ConstraintExpression)
                      == QgsFieldConstraints.ConstraintStrengthHard)
        if expression:
            constraints = field.constraints()
            expression = constraints.constraintExpression()
            description = constraints.constraintDescription()
            value = feature.attribute(field_index)
            exp = QgsExpression(expression)
            context = QgsExpressionContextUtils.createFeatureBasedContext(
                feature, layer.fields())
            context.appendScopes(
                QgsExpressionContextUtils.globalProjectLayerScopes(layer))
            if not bool(exp.evaluate(context)):
                if not description:
                    description = _('Expression check violation')
                _set_error(field.name(),
                           _("%s Expression: %s") % (description, expression))

    return errors
    def run(self):
        try:
            # Check if the layers look OK
            if self.inpvl is None or self.joinvl is None:
                self.status.emit('Layer is missing!')
                self.finished.emit(False, None)
                return
            # Check if there are features in the layers
            incount = 0
            if self.selectedinonly:
                incount = self.inpvl.selectedFeatureCount()
            else:
                incount = self.inpvl.featureCount()
            if incount == 0:
                self.status.emit('Input layer has no features!')
                self.finished.emit(False, None)
                return
            joincount = 0
            if self.selectedjoonly:
                joincount = self.joinvl.selectedFeatureCount()
            else:
                joincount = self.joinvl.featureCount()
            if joincount == 0:
                self.status.emit('Join layer has no features!')
                self.finished.emit(False, None)
                return
            # Get the wkbtype of the layers
            self.inpWkbType = self.inpvl.wkbType()
            self.joinWkbType = self.joinvl.wkbType()

            # Check if the input layer does not have geometries
            if (self.inpvl.geometryType() == QgsWkbTypes.NullGeometry):
                self.status.emit('No geometries in the input layer!')
                self.finished.emit(False, None)
                return
            # Check if the join layer does not have geometries
            if (self.joinvl.geometryType() == QgsWkbTypes.NullGeometry):
                self.status.emit('No geometries in the join layer!')
                self.finished.emit(False, None)
                return
            # Set the geometry type and prepare the output layer
            inpWkbTypetext = QgsWkbTypes.displayString(int(self.inpWkbType))
            # self.inputmulti = QgsWkbTypes.isMultiType(self.inpWkbType)
            # self.status.emit('wkbtype: ' + inpWkbTypetext)
            # geometryType = self.inpvl.geometryType()
            # geometrytypetext = 'Point'
            # if geometryType == QgsWkbTypes.PointGeometry:
            #     geometrytypetext = 'Point'
            # elif geometryType == QgsWkbTypes.LineGeometry:
            #     geometrytypetext = 'LineString'
            # elif geometryType == QgsWkbTypes.PolygonGeometry:
            #     geometrytypetext = 'Polygon'
            # if self.inputmulti:
            #     geometrytypetext = 'Multi' + geometrytypetext
            # geomttext = geometrytypetext

            geomttext = inpWkbTypetext
            # Set the coordinate reference system to the input
            # layer's CRS using authid (proj4 may be more robust)
            if self.inpvl.crs() is not None:
                geomttext = (geomttext + "?crs=" +
                             str(self.inpvl.crs().authid()))
            # Retrieve the fields from the input layer
            outfields = self.inpvl.fields().toList()
            # Retrieve the fields from the join layer
            if self.joinvl.fields() is not None:
                jfields = self.joinvl.fields().toList()
                for joinfield in jfields:
                    outfields.append(QgsField(self.joinprefix +
                                     str(joinfield.name()),
                                     joinfield.type()))
            else:
                self.status.emit('Unable to get any join layer fields')
            # Add the nearest neighbour distance field
            # Check if there is already a "distance" field
            # (should be avoided in the user interface)
            # Try a new name if there is a collission
            collission = True
            trynumber = 1
            distnameorg = self.distancename
            while collission:   # Iterate until there are no collissions
                collission = False
                for field in outfields:
                    # This check should not be necessary - handled in the UI
                    if field.name() == self.distancename:
                        self.status.emit(
                              'Distance field already exists - renaming!')
                        # self.abort = True
                        # self.finished.emit(False, None)
                        # break
                        collission = True
                        self.distancename = distnameorg + str(trynumber)
                        trynumber = trynumber + 1
            outfields.append(QgsField(self.distancename, QVariant.Double))
            # Create a memory layer using a CRS description
            self.mem_joinl = QgsVectorLayer(geomttext,
                                            self.outputlayername,
                                            "memory")
            # Set the CRS to the inputlayer's CRS
            self.mem_joinl.setCrs(self.inpvl.crs())
            self.mem_joinl.startEditing()
            # Add the fields
            for field in outfields:
                self.mem_joinl.dataProvider().addAttributes([field])
            # For an index to be used, the input layer has to be a
            # point layer, or the input layer geometries have to be
            # approximated to centroids, or the user has to have
            # accepted that a join layer index is used (for
            # non-point input layers).
            # (Could be extended to multipoint)
            if (self.inpWkbType == QgsWkbTypes.Point or
                    self.inpWkbType == QgsWkbTypes.Point25D or
                    self.approximateinputgeom or
                    self.nonpointexactindex):
                # Number of features in the join layer - used by
                # calculate_progress for the index creation
                if self.selectedjoonly:
                    self.feature_count = self.joinvl.selectedFeatureCount()
                else:
                    self.feature_count = self.joinvl.featureCount()
                # Create a spatial index to speed up joining
                self.status.emit('Creating join layer index...')
                # The number of elements that is needed to increment the
                # progressbar - set early in run()
                self.increment = self.feature_count // 1000
                self.joinlind = QgsSpatialIndex()
                # Include geometries to enable exact distance calculations
                # self.joinlind = QgsSpatialIndex(flags=[QgsSpatialIndex.FlagStoreFeatureGeometries])

                if self.selectedjoonly:
                    for feat in self.joinvl.getSelectedFeatures():
                        # Allow user abort
                        if self.abort is True:
                            break
                        self.joinlind.insertFeature(feat)
                        self.calculate_progress()
                else:
                    for feat in self.joinvl.getFeatures():
                        # Allow user abort
                        if self.abort is True:
                            break
                        self.joinlind.insertFeature(feat)
                        self.calculate_progress()
                self.status.emit('Join layer index created!')
                self.processed = 0
                self.percentage = 0
                # self.calculate_progress()

            # Is the join layer a multi-geometry layer?
            # self.joinmulti = QgsWkbTypes.isMultiType(self.joinWkbType)
            # Does the join layer contain multi geometries?
            # Try to check the first feature
            # This is not used for anything yet
            self.joinmulti = False
            if self.selectedjoonly:
                feats = self.joinvl.getSelectedFeatures()
            else:
                feats = self.joinvl.getFeatures()
            if feats is not None:
                testfeature = next(feats)
                feats.rewind()
                feats.close()
                if testfeature is not None:
                    if testfeature.hasGeometry():
                        if testfeature.geometry().isMultipart():
                            self.joinmulti = True
            # Prepare for the join by fetching the layers into memory
            # Add the input features to a list
            self.inputf = []
            if self.selectedinonly:
                for f in self.inpvl.getSelectedFeatures():
                    self.inputf.append(f)
            else:
                for f in self.inpvl.getFeatures():
                    self.inputf.append(f)
            # Add the join features to a list (used in the join)
            self.joinf = []
            if self.selectedjoonly:
                for f in self.joinvl.getSelectedFeatures():
                    self.joinf.append(f)
            else:
                for f in self.joinvl.getFeatures():
                    self.joinf.append(f)
            # Initialise the global variable that will contain the
            # result of the nearest neighbour spatial join (list of
            # features)
            self.features = []
            # Do the join!
            # Number of features in the input layer - used by
            # calculate_progress for the join operation
            if self.selectedinonly:
                self.feature_count = self.inpvl.selectedFeatureCount()
            else:
                self.feature_count = self.inpvl.featureCount()
            # The number of elements that is needed to increment the
            # progressbar - set early in run()
            self.increment = self.feature_count // 1000
            # Using the original features from the input layer
            for feat in self.inputf:
                # Allow user abort
                if self.abort is True:
                    break
                self.do_indexjoin(feat)
                self.calculate_progress()
            self.mem_joinl.dataProvider().addFeatures(self.features)
            self.status.emit('Join finished')
        except:
            import traceback
            self.error.emit(traceback.format_exc())
            self.finished.emit(False, None)
            if self.mem_joinl is not None:
                self.mem_joinl.rollBack()
        else:
            self.mem_joinl.commitChanges()
            if self.abort:
                self.finished.emit(False, None)
            else:
                self.status.emit('Delivering the memory layer...')
                self.finished.emit(True, self.mem_joinl)
Example #38
0
        def visit_node(tree_node):
            if isinstance(tree_node, QgsLayerTreeLayer):
                layer = tree_node.layer()
                layer_type = {
                    0: "vector",
                    1: "raster",
                    # 2: PluginLayer
                    # 3: MeshLayer
                }[layer.type()]
                source = layer.source()
                provider_type = layer.providerType()
                uri = ""

                if provider_type == "wms":
                    source_params = parse_qs(source)
                    uri = source_params["url"][0]
                elif provider_type == "postgres":
                    dp = layer.dataProvider()
                    uri = "postgresql://%s:%s" % (dp.uri().host(),
                                                  dp.uri().port())
                elif provider_type in ("ogr", "gdal"):
                    uri = "file://%s" % source.split("|")[0]
                elif provider_type == "spatialite":
                    match = dbname_pattern.search(source)
                    if match:
                        uri = "file://%s" % match.group(1)
                else:
                    uri = source

                extent = layer.extent()
                if not extent.isEmpty():
                    extent = map_settings.layerExtentToOutputExtent(
                        layer, layer.extent()).toRectF().getCoords()
                else:
                    extent = None
                info = {
                    "id":
                    layer.id(),
                    "name":
                    layer.name(),
                    "serverName":
                    layer.shortName()
                    if hasattr(layer, "shortName") else layer.name(),
                    "wfs":
                    layer.id() in wfs_layers,
                    "provider_type":
                    provider_type,
                    "projection":
                    layer.crs().authid(),
                    "type":
                    layer_type,
                    "source":
                    uri,
                    "extent":
                    extent,
                    "visible":
                    project.layerTreeRoot().findLayer(layer.id()).isVisible(),
                    "metadata": {
                        "title": layer.title(),
                        "abstract": layer.abstract(),
                        "keyword_list": layer.keywordList()
                    }
                }
                legend_url = layer.legendUrl()
                if legend_url:
                    info["legend_url"] = legend_url
                # if layer.isSpatial()
                if layer_type == "vector":
                    info["geom_type"] = ('POINT', 'LINE', 'POLYGON', None,
                                         None)[layer.geometryType()]
                    info["wkb_type"] = QgsWkbTypes.displayString(
                        layer.wkbType())
                    info["labels"] = layer.labelsEnabled()
                    info["attributes"] = self.get_layer_attributes(layer)
                    info["queryable"] = bool(info["attributes"]) and layer.id(
                    ) not in non_identifiable_layers and layer.id(
                    ) in wfs_layers
                    if info["attributes"]:
                        fields = layer.fields()
                        info["pk_attributes"] = [
                            fields.at(index).name() for index in
                            layer.dataProvider().pkAttributeIndexes()
                        ]

                if provider_type == "wms":
                    info["url"] = source_params["url"][0]
                    img_format = source_params.get("format", [None])[0]
                    if not img_format:
                        img_format = os.path.splitext(info["url"])[1].replace(
                            ".", "image/")

                    info["format"] = img_format

                    info["dpi"] = layer.dataProvider().dpi()
                    if "layers" in source_params:
                        info["wms_layers"] = source_params["layers"]

                if layer in layers_order:
                    info["drawing_order"] = layers_order.index(layer)
                if layer.attribution():
                    info["attribution"] = {
                        "title": layer.attribution(),
                        "url": layer.attributionUrl()
                    }
                return info
            else:
                children = []
                for child_tree_node in tree_node.children():
                    try:
                        info = visit_node(child_tree_node)
                        if info:
                            children.append(info)
                    except Exception as e:
                        if not skip_layers_with_error:
                            msg = "Failed to gather info from layer: '%s'" % child_tree_node.name(
                            )
                            raise WsError(msg, 405) from e
                return {"name": tree_node.name(), "layers": children}
Example #39
0
    def spatialInfo(self):
        ret = []
        if not self.table.geomType:
            return ret

        tbl = [
            (QApplication.translate("DBManagerPlugin", "Column:"),
             self.table.geomColumn),
            (QApplication.translate("DBManagerPlugin", "Geometry:"),
             self.table.geomType),
            (QApplication.translate("DBManagerPlugin",
                                    "Qgis Geometry type:"),
             QgsWkbTypes.displayString(self.table.wkbType))
        ]

        # only if we have info from geometry_columns
        if self.table.geomDim:
            tbl.append(
                (QApplication.translate(
                    "DBManagerPlugin",
                    "Dimension:"),
                 self.table.geomDim))

        srid = self.table.srid if self.table.srid else -1
        if srid != -1:
            sr_info = (
                self.table.database().connector.getSpatialRefInfo(srid))
        else:
            sr_info = QApplication.translate("DBManagerPlugin",
                                             "Undefined")
        if sr_info:
            tbl.append(
                (QApplication.translate(
                    "DBManagerPlugin", "Spatial ref:"),
                 u"{0} ({1})".format(sr_info, srid)))

        # estimated extent
        if not self.table.estimatedExtent:
            # estimated extent information is not displayed yet, so just block
            # table signals to avoid double refreshing
            # (infoViewer->refreshEstimatedExtent->tableChanged->infoViewer)
            self.table.blockSignals(True)
            self.table.refreshTableEstimatedExtent()
            self.table.blockSignals(False)

        if self.table.estimatedExtent:
            estimated_extent_str = (u"{:.9f}, {:.9f} - {:.9f}, "
                                    u"{:.9f}".format(
                                        *self.table.estimatedExtent))

            tbl.append(
                (QApplication.translate(
                    "DBManagerPlugin", "Estimated extent:"),
                 estimated_extent_str))

        # extent
        extent_str = None
        if self.table.extent and len(self.table.extent) == 4:
            extent_str = (u"{:.9f}, {:.9f} - {:.9f}, "
                          u"{:.9f}".format(*self.table.extent))
        elif self.table.rowCount > 0 or self.table.estimatedRowCount > 0:
            # Can't calculate an extent on empty layer
            extent_str = QApplication.translate(
                "DBManagerPlugin",
                '(unknown) (<a href="action:extent/get">find out</a>)')

        if extent_str:
            tbl.append(
                (QApplication.translate(
                    "DBManagerPlugin", "Extent:"),
                 extent_str))

        ret.append(HtmlTable(tbl))

        # Handle extent update metadata
        if (self.table.extent and
                self.table.extent != self.table.estimatedExtent and
                self.table.canUpdateMetadata()):
            ret.append(
                HtmlParagraph(
                    QApplication.translate(
                        "DBManagerPlugin",
                        (u'<warning> Metadata extent is different from'
                         u'real extent. You should <a href="action:extent'
                         u'/update">update it</a>!'))))

        # is there an entry in geometry_columns?
        if self.table.geomType.lower() == 'geometry':
            ret.append(
                HtmlParagraph(
                    QApplication.translate(
                        "DBManagerPlugin",
                        "<warning> There is no entry in geometry_columns!")))

        # find out whether the geometry column has spatial index on it
        if not self.table.isView:
            if not self.table.hasSpatialIndex():
                ret.append(
                    HtmlParagraph(
                        QApplication.translate(
                            "DBManagerPlugin",
                            (u'<warning> No spatial index defined (<a href='
                             u'"action:spatialindex/create">'
                             u'create it</a>).'))))

        return ret