Skip to content

Commit

Permalink
[needs-docs][processing] Port SAGA raster surface volume to native QG…
Browse files Browse the repository at this point in the history
…IS alg

The SAGA version of this algorithm is of limited use in QGIS, because the
volume calculated is embedded only in the SAGA terminal output. This prevents
it being saved to a file, or reused within a model as an input to a later
model step.

It's also very user-unfriendly, because users must know to manually scan
the algorithm log to find the SAGA output.

Given that the maths here is trivial, this commit ports the algorithm across
to be a native QGIS c++ algorithm. The algorithm duplicates the SAGA alg
1:1, but outputs the volume (and area) to either a HTML report, or a vector
table. Additionally, the outputs are exported as numeric outputs from the
algorithm, allowing them to be re-used within models.

(It's also considerably faster, because it avoids the forced conversion
to SAGA raster format)

Fixes #8607 (properly, even though that report is closed)
  • Loading branch information
nyalldawson committed Jan 21, 2019
1 parent e3fda18 commit 195d98f
Show file tree
Hide file tree
Showing 32 changed files with 1,114 additions and 0 deletions.
Binary file not shown.
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ogr.maptools.org/ surface_vol_above.xsd"
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy><gml:null>missing</gml:null></gml:boundedBy>

<gml:featureMember>
<ogr:surface_vol_above fid="surface_vol_above.0">
<ogr:volume>0.06480527</ogr:volume>
<ogr:deg2>0.00095901</ogr:deg2>
<ogr:pixel_count>95901</ogr:pixel_count>
</ogr:surface_vol_above>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -0,0 +1,6 @@
<html><head><meta http-equiv="Content-Type" content="text/html;charset=utf-8"/></head><body>
<p>Analyzed file: /home/nyall/dev/QGIS/python/plugins/processing/tests/testdata/dem.tif (band 1)</p>
<p>Volume: 0.0648052733680633</p>
<p>Pixel count: 95901</p>
<p>Area: 0.0009590099999998638 deg2</p>
</body></html>
@@ -0,0 +1,45 @@
<?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" elementFormDefault="qualified" version="1.0">
<xs:import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/2.1.2/feature.xsd"/>
<xs:element name="FeatureCollection" type="ogr:FeatureCollectionType" substitutionGroup="gml:_FeatureCollection"/>
<xs:complexType name="FeatureCollectionType">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureCollectionType">
<xs:attribute name="lockId" type="xs:string" use="optional"/>
<xs:attribute name="scope" type="xs:string" use="optional"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="surface_vol_above" type="ogr:surface_vol_above_Type" substitutionGroup="gml:_Feature"/>
<xs:complexType name="surface_vol_above_Type">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureType">
<xs:sequence>
<xs:element name="volume" 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="deg2" 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="pixel_count" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:long">
<xs:totalDigits value="20"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ogr.maptools.org/ surface_vol_above_crs.xsd"
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy><gml:null>missing</gml:null></gml:boundedBy>

<gml:featureMember>
<ogr:surface_vol_above_crs fid="surface_vol_above_crs.0">
<ogr:volume>413784918.00990051</ogr:volume>
<ogr:m2>11497732.58555590</ogr:m2>
<ogr:pixel_count>64692</ogr:pixel_count>
</ogr:surface_vol_above_crs>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -0,0 +1,6 @@
<html><head><meta http-equiv="Content-Type" content="text/html;charset=utf-8"/></head><body>
<p>Analyzed file: /home/nyall/dev/QGIS/python/plugins/processing/tests/testdata/custom/dem_crs.tif (band 1)</p>
<p>Volume: 413784918.0099005</p>
<p>Pixel count: 64692</p>
<p>Area: 11497732.5855559 m2</p>
</body></html>
@@ -0,0 +1,45 @@
<?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" elementFormDefault="qualified" version="1.0">
<xs:import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/2.1.2/feature.xsd"/>
<xs:element name="FeatureCollection" type="ogr:FeatureCollectionType" substitutionGroup="gml:_FeatureCollection"/>
<xs:complexType name="FeatureCollectionType">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureCollectionType">
<xs:attribute name="lockId" type="xs:string" use="optional"/>
<xs:attribute name="scope" type="xs:string" use="optional"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="surface_vol_above_crs" type="ogr:surface_vol_above_crs_Type" substitutionGroup="gml:_Feature"/>
<xs:complexType name="surface_vol_above_crs_Type">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureType">
<xs:sequence>
<xs:element name="volume" 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="m2" 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="pixel_count" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:long">
<xs:totalDigits value="20"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ogr.maptools.org/ surface_vol_add.xsd"
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy><gml:null>missing</gml:null></gml:boundedBy>

<gml:featureMember>
<ogr:surface_vol_add fid="surface_vol_add.0">
<ogr:volume>0.06802753</ogr:volume>
<ogr:deg2>0.00130550</ogr:deg2>
<ogr:pixel_count>130550</ogr:pixel_count>
</ogr:surface_vol_add>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -0,0 +1,6 @@
<html><head><meta http-equiv="Content-Type" content="text/html;charset=utf-8"/></head><body>
<p>Analyzed file: /home/nyall/dev/QGIS/python/plugins/processing/tests/testdata/dem.tif (band 1)</p>
<p>Volume: 0.06802752691184032</p>
<p>Pixel count: 130550</p>
<p>Area: 0.001305499999999814 deg2</p>
</body></html>
@@ -0,0 +1,45 @@
<?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" elementFormDefault="qualified" version="1.0">
<xs:import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/2.1.2/feature.xsd"/>
<xs:element name="FeatureCollection" type="ogr:FeatureCollectionType" substitutionGroup="gml:_FeatureCollection"/>
<xs:complexType name="FeatureCollectionType">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureCollectionType">
<xs:attribute name="lockId" type="xs:string" use="optional"/>
<xs:attribute name="scope" type="xs:string" use="optional"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="surface_vol_add" type="ogr:surface_vol_add_Type" substitutionGroup="gml:_Feature"/>
<xs:complexType name="surface_vol_add_Type">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureType">
<xs:sequence>
<xs:element name="volume" 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="deg2" 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="pixel_count" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:long">
<xs:totalDigits value="20"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ogr.maptools.org/ surface_vol_add_crs.xsd"
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy><gml:null>missing</gml:null></gml:boundedBy>

<gml:featureMember>
<ogr:surface_vol_add_crs fid="surface_vol_add_crs.0">
<ogr:volume>893436802.88886535</ogr:volume>
<ogr:m2>23202698.77333090</ogr:m2>
<ogr:pixel_count>130550</ogr:pixel_count>
</ogr:surface_vol_add_crs>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -0,0 +1,6 @@
<html><head><meta http-equiv="Content-Type" content="text/html;charset=utf-8"/></head><body>
<p>Analyzed file: /home/nyall/dev/QGIS/python/plugins/processing/tests/testdata/custom/dem_crs.tif (band 1)</p>
<p>Volume: 893436802.8888654</p>
<p>Pixel count: 130550</p>
<p>Area: 23202698.7733309 m2</p>
</body></html>
@@ -0,0 +1,45 @@
<?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" elementFormDefault="qualified" version="1.0">
<xs:import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/2.1.2/feature.xsd"/>
<xs:element name="FeatureCollection" type="ogr:FeatureCollectionType" substitutionGroup="gml:_FeatureCollection"/>
<xs:complexType name="FeatureCollectionType">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureCollectionType">
<xs:attribute name="lockId" type="xs:string" use="optional"/>
<xs:attribute name="scope" type="xs:string" use="optional"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="surface_vol_add_crs" type="ogr:surface_vol_add_crs_Type" substitutionGroup="gml:_Feature"/>
<xs:complexType name="surface_vol_add_crs_Type">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureType">
<xs:sequence>
<xs:element name="volume" 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="m2" 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="pixel_count" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:long">
<xs:totalDigits value="20"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ogr.maptools.org/ surface_vol_below.xsd"
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy><gml:null>missing</gml:null></gml:boundedBy>

<gml:featureMember>
<ogr:surface_vol_below fid="surface_vol_below.0">
<ogr:volume>-0.00322225</ogr:volume>
<ogr:deg2>0.00034600</ogr:deg2>
<ogr:pixel_count>34600</ogr:pixel_count>
</ogr:surface_vol_below>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -0,0 +1,6 @@
<html><head><meta http-equiv="Content-Type" content="text/html;charset=utf-8"/></head><body>
<p>Analyzed file: /home/nyall/dev/QGIS/python/plugins/processing/tests/testdata/dem.tif (band 1)</p>
<p>Volume: -0.003222253543777008</p>
<p>Pixel count: 34600</p>
<p>Area: 0.0003459999999999508 deg2</p>
</body></html>
@@ -0,0 +1,45 @@
<?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" elementFormDefault="qualified" version="1.0">
<xs:import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/2.1.2/feature.xsd"/>
<xs:element name="FeatureCollection" type="ogr:FeatureCollectionType" substitutionGroup="gml:_FeatureCollection"/>
<xs:complexType name="FeatureCollectionType">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureCollectionType">
<xs:attribute name="lockId" type="xs:string" use="optional"/>
<xs:attribute name="scope" type="xs:string" use="optional"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="surface_vol_below" type="ogr:surface_vol_below_Type" substitutionGroup="gml:_Feature"/>
<xs:complexType name="surface_vol_below_Type">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureType">
<xs:sequence>
<xs:element name="volume" 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="deg2" 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="pixel_count" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:long">
<xs:totalDigits value="20"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ogr.maptools.org/ surface_vol_below_crs.xsd"
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy><gml:null>missing</gml:null></gml:boundedBy>

<gml:featureMember>
<ogr:surface_vol_below_crs fid="surface_vol_below_crs.0">
<ogr:volume>-479651884.87896484</ogr:volume>
<ogr:m2>11669775.57607742</ogr:m2>
<ogr:pixel_count>65660</ogr:pixel_count>
</ogr:surface_vol_below_crs>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -0,0 +1,6 @@
<html><head><meta http-equiv="Content-Type" content="text/html;charset=utf-8"/></head><body>
<p>Analyzed file: /home/nyall/dev/QGIS/python/plugins/processing/tests/testdata/custom/dem_crs.tif (band 1)</p>
<p>Volume: -479651884.8789648</p>
<p>Pixel count: 65660</p>
<p>Area: 11669775.57607742 m2</p>
</body></html>

0 comments on commit 195d98f

Please sign in to comment.