Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feature] Add raster zonal min/max algorithm #59358

Merged
merged 5 commits into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions python/PyQt6/core/auto_additions/qgis.py
Original file line number Diff line number Diff line change
Expand Up @@ -10429,7 +10429,10 @@
Qgis.ZonalStatistic.Majority.__doc__ = "Majority of pixel values"
Qgis.ZonalStatistic.Variety.__doc__ = "Variety (count of distinct) pixel values"
Qgis.ZonalStatistic.Variance.__doc__ = "Variance of pixel values"
Qgis.ZonalStatistic.All.__doc__ = "All statistics"
Qgis.ZonalStatistic.MinimumPoint.__doc__ = "Pixel centroid for minimum pixel value \n.. versionadded:: 3.42"
Qgis.ZonalStatistic.MaximumPoint.__doc__ = "Pixel centroid for maximum pixel value \n.. versionadded:: 3.42"
Qgis.ZonalStatistic.All.__doc__ = "All statistics. For QGIS 3.x this includes ONLY numeric statistics, but for 4.0 this will be extended to included non-numeric statistics. Consider using AllNumeric instead."
Qgis.ZonalStatistic.AllNumeric.__doc__ = "All numeric statistics \n.. versionadded:: 3.42"
Qgis.ZonalStatistic.Default.__doc__ = "Default statistics"
Qgis.ZonalStatistic.__doc__ = """Statistics to be calculated during a zonal statistics operation.

Expand All @@ -10447,7 +10450,19 @@
* ``Majority``: Majority of pixel values
* ``Variety``: Variety (count of distinct) pixel values
* ``Variance``: Variance of pixel values
* ``All``: All statistics
* ``MinimumPoint``: Pixel centroid for minimum pixel value

.. versionadded:: 3.42

* ``MaximumPoint``: Pixel centroid for maximum pixel value

.. versionadded:: 3.42

* ``All``: All statistics. For QGIS 3.x this includes ONLY numeric statistics, but for 4.0 this will be extended to included non-numeric statistics. Consider using AllNumeric instead.
* ``AllNumeric``: All numeric statistics

.. versionadded:: 3.42

* ``Default``: Default statistics

"""
Expand Down
4 changes: 4 additions & 0 deletions python/PyQt6/core/auto_generated/qgis.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -3017,6 +3017,7 @@ The development version
Other,
};


enum class ZonalStatistic /BaseType=IntFlag/
{
Count,
Expand All @@ -3031,7 +3032,10 @@ The development version
Majority,
Variety,
Variance,
MinimumPoint,
MaximumPoint,
All,
AllNumeric,
Default,
};

Expand Down
19 changes: 17 additions & 2 deletions python/core/auto_additions/qgis.py
Original file line number Diff line number Diff line change
Expand Up @@ -10345,7 +10345,10 @@
Qgis.ZonalStatistic.Majority.__doc__ = "Majority of pixel values"
Qgis.ZonalStatistic.Variety.__doc__ = "Variety (count of distinct) pixel values"
Qgis.ZonalStatistic.Variance.__doc__ = "Variance of pixel values"
Qgis.ZonalStatistic.All.__doc__ = "All statistics"
Qgis.ZonalStatistic.MinimumPoint.__doc__ = "Pixel centroid for minimum pixel value \n.. versionadded:: 3.42"
Qgis.ZonalStatistic.MaximumPoint.__doc__ = "Pixel centroid for maximum pixel value \n.. versionadded:: 3.42"
Qgis.ZonalStatistic.All.__doc__ = "All statistics. For QGIS 3.x this includes ONLY numeric statistics, but for 4.0 this will be extended to included non-numeric statistics. Consider using AllNumeric instead."
Qgis.ZonalStatistic.AllNumeric.__doc__ = "All numeric statistics \n.. versionadded:: 3.42"
Qgis.ZonalStatistic.Default.__doc__ = "Default statistics"
Qgis.ZonalStatistic.__doc__ = """Statistics to be calculated during a zonal statistics operation.

Expand All @@ -10363,7 +10366,19 @@
* ``Majority``: Majority of pixel values
* ``Variety``: Variety (count of distinct) pixel values
* ``Variance``: Variance of pixel values
* ``All``: All statistics
* ``MinimumPoint``: Pixel centroid for minimum pixel value

.. versionadded:: 3.42

* ``MaximumPoint``: Pixel centroid for maximum pixel value

.. versionadded:: 3.42

* ``All``: All statistics. For QGIS 3.x this includes ONLY numeric statistics, but for 4.0 this will be extended to included non-numeric statistics. Consider using AllNumeric instead.
* ``AllNumeric``: All numeric statistics

.. versionadded:: 3.42

* ``Default``: Default statistics

"""
Expand Down
4 changes: 4 additions & 0 deletions python/core/auto_generated/qgis.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -3017,6 +3017,7 @@ The development version
Other,
};


enum class ZonalStatistic
{
Count,
Expand All @@ -3031,7 +3032,10 @@ The development version
Majority,
Variety,
Variance,
MinimumPoint,
MaximumPoint,
All,
AllNumeric,
Default,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<gml:boundedBy><gml:Envelope srsName="urn:ogc:def:crs:EPSG::4326"><gml:lowerCorner>45.7964514376 18.6964479442</gml:lowerCorner><gml:upperCorner>45.7964514376 18.6964479442</gml:upperCorner></gml:Envelope></gml:boundedBy>
<ogr:geometryProperty><gml:Point srsName="urn:ogc:def:crs:EPSG::4326" gml:id="raster_max.geom.0"><gml:pos>45.7964514376 18.6964479442</gml:pos></gml:Point></ogr:geometryProperty>
<ogr:value>243.00000000</ogr:value>
<ogr:extremum>maximum</ogr:extremum>
<ogr:extremum_type>maximum</ogr:extremum_type>
</ogr:raster_max>
</ogr:featureMember>
</ogr:FeatureCollection>
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="extremum" nillable="true" minOccurs="0" maxOccurs="1">
<xs:element name="extremum_type" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:string">
</xs:restriction>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<gml:boundedBy><gml:Envelope srsName="urn:ogc:def:crs:EPSG::4326"><gml:lowerCorner>45.8027514376 18.6786479442</gml:lowerCorner><gml:upperCorner>45.8027514376 18.6786479442</gml:upperCorner></gml:Envelope></gml:boundedBy>
<ogr:geometryProperty><gml:Point srsName="urn:ogc:def:crs:EPSG::4326" gml:id="raster_min.geom.0"><gml:pos>45.8027514376 18.6786479442</gml:pos></gml:Point></ogr:geometryProperty>
<ogr:value>85.00000000</ogr:value>
<ogr:extremum>minimum</ogr:extremum>
<ogr:extremum_type>minimum</ogr:extremum_type>
</ogr:raster_min>
</ogr:featureMember>
</ogr:FeatureCollection>
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="extremum" nillable="true" minOccurs="0" maxOccurs="1">
<xs:element name="extremum_type" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:string">
</xs:restriction>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@
<gml:boundedBy><gml:Envelope srsName="urn:ogc:def:crs:EPSG::4326"><gml:lowerCorner>45.8027514376 18.6786479442</gml:lowerCorner><gml:upperCorner>45.8027514376 18.6786479442</gml:upperCorner></gml:Envelope></gml:boundedBy>
<ogr:geometryProperty><gml:Point srsName="urn:ogc:def:crs:EPSG::4326" gml:id="raster_min_max.geom.0"><gml:pos>45.8027514376 18.6786479442</gml:pos></gml:Point></ogr:geometryProperty>
<ogr:value>85.00000000</ogr:value>
<ogr:extremum>minimum</ogr:extremum>
<ogr:extremum_type>minimum</ogr:extremum_type>
</ogr:raster_min_max>
</ogr:featureMember>
<ogr:featureMember>
<ogr:raster_min_max gml:id="raster_min_max.1">
<gml:boundedBy><gml:Envelope srsName="urn:ogc:def:crs:EPSG::4326"><gml:lowerCorner>45.7964514376 18.6964479442</gml:lowerCorner><gml:upperCorner>45.7964514376 18.6964479442</gml:upperCorner></gml:Envelope></gml:boundedBy>
<ogr:geometryProperty><gml:Point srsName="urn:ogc:def:crs:EPSG::4326" gml:id="raster_min_max.geom.1"><gml:pos>45.7964514376 18.6964479442</gml:pos></gml:Point></ogr:geometryProperty>
<ogr:value>243.00000000</ogr:value>
<ogr:extremum>maximum</ogr:extremum>
<ogr:extremum_type>maximum</ogr:extremum_type>
</ogr:raster_min_max>
</ogr:featureMember>
</ogr:FeatureCollection>
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="extremum" nillable="true" minOccurs="0" maxOccurs="1">
<xs:element name="extremum_type" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:string">
</xs:restriction>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
gml:id="aFeatureCollection"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ogr.maptools.org/ raster_zonal_extremum.xsd"
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml/3.2">
<gml:boundedBy><gml:Envelope srsName="urn:ogc:def:crs:EPSG::3857"><gml:lowerCorner>2078752.11232507 5745092.4177069</gml:lowerCorner><gml:upperCorner>2081279.06482292 5749099.83092514</gml:upperCorner></gml:Envelope></gml:boundedBy>

<ogr:featureMember>
<ogr:raster_zonal_extremum gml:id="raster_zonal_extremum.0">
<gml:boundedBy><gml:Envelope srsName="urn:ogc:def:crs:EPSG::3857"><gml:lowerCorner>2078985.88326099 5746736.89404743</gml:lowerCorner><gml:upperCorner>2078985.88326099 5746736.89404743</gml:upperCorner></gml:Envelope></gml:boundedBy>
<ogr:geometryProperty><gml:Point srsName="urn:ogc:def:crs:EPSG::3857" gml:id="raster_zonal_extremum.geom.0"><gml:pos>2078985.88326099 5746736.89404743</gml:pos></gml:Point></ogr:geometryProperty>
<ogr:zone>zone 1</ogr:zone>
<ogr:value>97.50000000</ogr:value>
<ogr:extremum_type>minimum</ogr:extremum_type>
</ogr:raster_zonal_extremum>
</ogr:featureMember>
<ogr:featureMember>
<ogr:raster_zonal_extremum gml:id="raster_zonal_extremum.1">
<gml:boundedBy><gml:Envelope srsName="urn:ogc:def:crs:EPSG::3857"><gml:lowerCorner>2078752.11232507 5745092.4177069</gml:lowerCorner><gml:upperCorner>2078752.11232507 5745092.4177069</gml:upperCorner></gml:Envelope></gml:boundedBy>
<ogr:geometryProperty><gml:Point srsName="urn:ogc:def:crs:EPSG::3857" gml:id="raster_zonal_extremum.geom.1"><gml:pos>2078752.11232507 5745092.4177069</gml:pos></gml:Point></ogr:geometryProperty>
<ogr:zone>zone 1</ogr:zone>
<ogr:value>219.19999695</ogr:value>
<ogr:extremum_type>maximum</ogr:extremum_type>
</ogr:raster_zonal_extremum>
</ogr:featureMember>
<ogr:featureMember>
<ogr:raster_zonal_extremum gml:id="raster_zonal_extremum.2">
<gml:boundedBy><gml:Envelope srsName="urn:ogc:def:crs:EPSG::3857"><gml:lowerCorner>2080499.82836984 5749099.83092514</gml:lowerCorner><gml:upperCorner>2080499.82836984 5749099.83092514</gml:upperCorner></gml:Envelope></gml:boundedBy>
<ogr:geometryProperty><gml:Point srsName="urn:ogc:def:crs:EPSG::3857" gml:id="raster_zonal_extremum.geom.2"><gml:pos>2080499.82836984 5749099.83092514</gml:pos></gml:Point></ogr:geometryProperty>
<ogr:zone>zone 2</ogr:zone>
<ogr:value>108.06781769</ogr:value>
<ogr:extremum_type>minimum</ogr:extremum_type>
</ogr:raster_zonal_extremum>
</ogr:featureMember>
<ogr:featureMember>
<ogr:raster_zonal_extremum gml:id="raster_zonal_extremum.3">
<gml:boundedBy><gml:Envelope srsName="urn:ogc:def:crs:EPSG::3857"><gml:lowerCorner>2081279.06482292 5747790.6361686</gml:lowerCorner><gml:upperCorner>2081279.06482292 5747790.6361686</gml:upperCorner></gml:Envelope></gml:boundedBy>
<ogr:geometryProperty><gml:Point srsName="urn:ogc:def:crs:EPSG::3857" gml:id="raster_zonal_extremum.geom.3"><gml:pos>2081279.06482292 5747790.6361686</gml:pos></gml:Point></ogr:geometryProperty>
<ogr:zone>zone 2</ogr:zone>
<ogr:value>243.00000000</ogr:value>
<ogr:extremum_type>maximum</ogr:extremum_type>
</ogr:raster_zonal_extremum>
</ogr:featureMember>
<ogr:featureMember>
<ogr:raster_zonal_extremum gml:id="raster_zonal_extremum.4">
<gml:boundedBy><gml:Envelope srsName="urn:ogc:def:crs:EPSG::3857"><gml:lowerCorner>2080421.90472453 5747072.17563143</gml:lowerCorner><gml:upperCorner>2080421.90472453 5747072.17563143</gml:upperCorner></gml:Envelope></gml:boundedBy>
<ogr:geometryProperty><gml:Point srsName="urn:ogc:def:crs:EPSG::3857" gml:id="raster_zonal_extremum.geom.4"><gml:pos>2080421.90472453 5747072.17563143</gml:pos></gml:Point></ogr:geometryProperty>
<ogr:zone>zone 3</ogr:zone>
<ogr:value>163.57766724</ogr:value>
<ogr:extremum_type>minimum</ogr:extremum_type>
</ogr:raster_zonal_extremum>
</ogr:featureMember>
<ogr:featureMember>
<ogr:raster_zonal_extremum gml:id="raster_zonal_extremum.5">
<gml:boundedBy><gml:Envelope srsName="urn:ogc:def:crs:EPSG::3857"><gml:lowerCorner>2080433.03667386 5747056.20984171</gml:lowerCorner><gml:upperCorner>2080433.03667386 5747056.20984171</gml:upperCorner></gml:Envelope></gml:boundedBy>
<ogr:geometryProperty><gml:Point srsName="urn:ogc:def:crs:EPSG::3857" gml:id="raster_zonal_extremum.geom.5"><gml:pos>2080433.03667386 5747056.20984171</gml:pos></gml:Point></ogr:geometryProperty>
<ogr:zone>zone 3</ogr:zone>
<ogr:value>170.00000000</ogr:value>
<ogr:extremum_type>maximum</ogr:extremum_type>
</ogr:raster_zonal_extremum>
</ogr:featureMember>
</ogr:FeatureCollection>
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
targetNamespace="http://ogr.maptools.org/"
xmlns:ogr="http://ogr.maptools.org/"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:gmlsf="http://www.opengis.net/gmlsf/2.0"
elementFormDefault="qualified"
version="1.0">
<xs:annotation>
<xs:appinfo source="http://schemas.opengis.net/gmlsfProfile/2.0/gmlsfLevels.xsd">
<gmlsf:ComplianceLevel>0</gmlsf:ComplianceLevel>
</xs:appinfo>
</xs:annotation>
<xs:import namespace="http://www.opengis.net/gml/3.2" schemaLocation="http://schemas.opengis.net/gml/3.2.1/gml.xsd"/>
<xs:import namespace="http://www.opengis.net/gmlsf/2.0" schemaLocation="http://schemas.opengis.net/gmlsfProfile/2.0/gmlsfLevels.xsd"/>
<xs:element name="FeatureCollection" type="ogr:FeatureCollectionType" substitutionGroup="gml:AbstractFeature"/>
<xs:complexType name="FeatureCollectionType">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureType">
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="featureMember">
<xs:complexType>
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureMemberType">
<xs:sequence>
<xs:element ref="gml:AbstractFeature"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="raster_zonal_extremum" type="ogr:raster_zonal_extremum_Type" substitutionGroup="gml:AbstractFeature"/>
<xs:complexType name="raster_zonal_extremum_Type">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureType">
<xs:sequence>
<xs:element name="geometryProperty" type="gml:PointPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/><!-- srsName="urn:ogc:def:crs:EPSG::3857" -->
<xs:element name="zone" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:string">
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="value" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:decimal">
<xs:totalDigits value="21"/>
<xs:fractionDigits value="8"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="extremum_type" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:string">
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
Original file line number Diff line number Diff line change
Expand Up @@ -285,3 +285,18 @@ tests:
OUTPUT:
name: expected/raster_max.gml
type: vector

- algorithm: native:zonalminmaxpoint
name: Raster zonal min max
params:
INPUT:
name: custom/dem_zones.geojson
type: vector
INPUT_RASTER:
name: custom/dem_crs.tif
type: raster
RASTER_BAND: 1
results:
OUTPUT:
name: expected/raster_zonal_extremum.gml
type: vector
1 change: 1 addition & 0 deletions src/analysis/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ set(QGIS_ANALYSIS_SRCS
processing/qgsalgorithmwritevectortiles.cpp
processing/qgsalgorithmxyztiles.cpp
processing/qgsalgorithmzonalhistogram.cpp
processing/qgsalgorithmzonalminmaxpoint.cpp
processing/qgsalgorithmzonalstatistics.cpp
processing/qgsalgorithmzonalstatisticsfeaturebased.cpp
processing/qgsbookmarkalgorithms.cpp
Expand Down
2 changes: 1 addition & 1 deletion src/analysis/processing/qgsalgorithmrasterminmax.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ QVariantMap QgsRasterMinMaxAlgorithm::processAlgorithm( const QVariantMap &param
{
QgsFields outFields;
outFields.append( QgsField( QStringLiteral( "value" ), QMetaType::Type::Double, QString(), 20, 8 ) );
outFields.append( QgsField( QStringLiteral( "extremum" ), QMetaType::Type::QString ) );
outFields.append( QgsField( QStringLiteral( "extremum_type" ), QMetaType::Type::QString ) );
sink.reset( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, outFields, Qgis::WkbType::Point, mCrs ) );
if ( !sink )
throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
Expand Down
4 changes: 2 additions & 2 deletions src/analysis/processing/qgsalgorithmzonalhistogram.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,14 +142,14 @@ QVariantMap QgsZonalHistogramAlgorithm::processAlgorithm( const QVariantMap &par

QHash< double, qgssize > fUniqueValues;
QgsRasterAnalysisUtils::statisticsFromMiddlePointTest( mRasterInterface.get(), mRasterBand, featureGeometry, nCellsX, nCellsY, mCellSizeX, mCellSizeY,
rasterBlockExtent, [ &fUniqueValues]( double value ) { fUniqueValues[value]++; }, false );
rasterBlockExtent, [ &fUniqueValues]( double value, const QgsPointXY & ) { fUniqueValues[value]++; }, false );

if ( fUniqueValues.count() < 1 )
{
// The cell resolution is probably larger than the polygon area. We switch to slower precise pixel - polygon intersection in this case
// TODO: eventually deal with weight if needed
QgsRasterAnalysisUtils::statisticsFromPreciseIntersection( mRasterInterface.get(), mRasterBand, featureGeometry, nCellsX, nCellsY, mCellSizeX, mCellSizeY,
rasterBlockExtent, [ &fUniqueValues]( double value, double ) { fUniqueValues[value]++; }, false );
rasterBlockExtent, [ &fUniqueValues]( double value, double, const QgsPointXY & ) { fUniqueValues[value]++; }, false );
}

for ( auto it = fUniqueValues.constBegin(); it != fUniqueValues.constEnd(); ++it )
Expand Down
Loading
Loading