Skip to content

Commit d2513e0

Browse files
committedApr 24, 2018
Port Difference & Sym.Diff. to C++, cleanups and tests
1 parent 120d5b1 commit d2513e0

21 files changed

+858
-296
lines changed
 

‎python/plugins/processing/algs/help/qgis.yaml

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -135,11 +135,6 @@ qgis:densifygeometriesgivenaninterval: >
135135

136136
The distance is expressed in the same units used by the layer CRS.
137137

138-
qgis:difference: >
139-
This algorithm extracts features from the Input layer that fall outside, or partially overlap, features in the Difference layer. Input layer features that partially overlap the difference layer feature(s) are split along the boundary of the difference layer feature(s) and only the portions outside the difference layer features are retained.
140-
141-
Attributes are not modified.
142-
143138
qgis:dissolve: >
144139
This algorithm takes a polygon or line vector layer and combines their geometries into new geometries. One or more attributes can be specified to dissolve only geometries belonging to the same class (having the same value for the specified attributes), alternatively all geometries can be dissolved.
145140

@@ -511,10 +506,6 @@ qgis:sumlinelengths: >
511506

512507
The resulting layer has the same features as the input polygon layer, but with two additional attributes containing the length and count of the lines across each polygon. The names of these two fields can be configured in the algorithm parameters.
513508

514-
qgis:symmetricaldifference: >
515-
This algorithm creates a layer containing features from both the Input and Difference layers but with the overlapping areas between the two layers removed. The attribute table of the Symmetrical Difference layer contains attributes from both the Input and Difference layers.
516-
517-
518509
qgis:texttofloat: >
519510
This algorithm modifies the type of a given attribute in a vector layer, converting a text attribute containing numeric strings into a numeric attribute.
520511

‎python/plugins/processing/algs/qgis/Difference.py

Lines changed: 0 additions & 121 deletions
This file was deleted.

‎python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@
5757
from .DeleteDuplicateGeometries import DeleteDuplicateGeometries
5858
from .DensifyGeometries import DensifyGeometries
5959
from .DensifyGeometriesInterval import DensifyGeometriesInterval
60-
from .Difference import Difference
6160
from .EliminateSelection import EliminateSelection
6261
from .ExecuteSQL import ExecuteSQL
6362
from .ExportGeometryInfo import ExportGeometryInfo
@@ -134,7 +133,6 @@
134133
from .SpatialJoinSummary import SpatialJoinSummary
135134
from .StatisticsByCategories import StatisticsByCategories
136135
from .SumLines import SumLines
137-
from .SymmetricalDifference import SymmetricalDifference
138136
from .TextToFloat import TextToFloat
139137
from .TinInterpolation import TinInterpolation
140138
from .TopoColors import TopoColor
@@ -175,7 +173,6 @@ def getAlgs(self):
175173
DeleteDuplicateGeometries(),
176174
DensifyGeometries(),
177175
DensifyGeometriesInterval(),
178-
Difference(),
179176
EliminateSelection(),
180177
ExecuteSQL(),
181178
ExportGeometryInfo(),
@@ -252,7 +249,6 @@ def getAlgs(self):
252249
SpatialJoinSummary(),
253250
StatisticsByCategories(),
254251
SumLines(),
255-
SymmetricalDifference(),
256252
TextToFloat(),
257253
TinInterpolation(),
258254
TopoColor(),

‎python/plugins/processing/algs/qgis/SymmetricalDifference.py

Lines changed: 0 additions & 162 deletions
This file was deleted.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<ogr:FeatureCollection
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://ogr.maptools.org/ difference1_a_b.xsd"
5+
xmlns:ogr="http://ogr.maptools.org/"
6+
xmlns:gml="http://www.opengis.net/gml">
7+
<gml:boundedBy>
8+
<gml:Box>
9+
<gml:coord><gml:X>1</gml:X><gml:Y>3</gml:Y></gml:coord>
10+
<gml:coord><gml:X>9</gml:X><gml:Y>11</gml:Y></gml:coord>
11+
</gml:Box>
12+
</gml:boundedBy>
13+
14+
<gml:featureMember>
15+
<ogr:difference1_a_b fid="difference1_a_b.0">
16+
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:3857"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>2,5 2,3 1,3 1,5 2,5</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>1,6 1,11 8,11 8,10 2,10 2,6 1,6</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
17+
<ogr:id_a>A1</ogr:id_a>
18+
</ogr:difference1_a_b>
19+
</gml:featureMember>
20+
<gml:featureMember>
21+
<ogr:difference1_a_b fid="difference1_a_b.1">
22+
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:3857"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>3,3 3,4 4,4 4,3 3,3</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
23+
<ogr:id_a>A4</ogr:id_a>
24+
</ogr:difference1_a_b>
25+
</gml:featureMember>
26+
<gml:featureMember>
27+
<ogr:difference1_a_b fid="difference1_a_b.2">
28+
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:3857"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>4,6 6,6 6,5 4,5 4,6</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
29+
<ogr:id_a>A2</ogr:id_a>
30+
</ogr:difference1_a_b>
31+
</gml:featureMember>
32+
<gml:featureMember>
33+
<ogr:difference1_a_b fid="difference1_a_b.3">
34+
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:3857"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>7,7 6,7 6,8 7,8 7,7</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>8,8 9,8 9,7 8,7 8,8</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
35+
<ogr:id_a>A3</ogr:id_a>
36+
</ogr:difference1_a_b>
37+
</gml:featureMember>
38+
</ogr:FeatureCollection>
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<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">
3+
<xs:import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/2.1.2/feature.xsd"/>
4+
<xs:element name="FeatureCollection" type="ogr:FeatureCollectionType" substitutionGroup="gml:_FeatureCollection"/>
5+
<xs:complexType name="FeatureCollectionType">
6+
<xs:complexContent>
7+
<xs:extension base="gml:AbstractFeatureCollectionType">
8+
<xs:attribute name="lockId" type="xs:string" use="optional"/>
9+
<xs:attribute name="scope" type="xs:string" use="optional"/>
10+
</xs:extension>
11+
</xs:complexContent>
12+
</xs:complexType>
13+
<xs:element name="difference1_a_b" type="ogr:difference1_a_b_Type" substitutionGroup="gml:_Feature"/>
14+
<xs:complexType name="difference1_a_b_Type">
15+
<xs:complexContent>
16+
<xs:extension base="gml:AbstractFeatureType">
17+
<xs:sequence>
18+
<xs:element name="geometryProperty" type="gml:MultiPolygonPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
19+
<xs:element name="id_a" nillable="true" minOccurs="0" maxOccurs="1">
20+
<xs:simpleType>
21+
<xs:restriction base="xs:string">
22+
<xs:maxLength value="255"/>
23+
</xs:restriction>
24+
</xs:simpleType>
25+
</xs:element>
26+
</xs:sequence>
27+
</xs:extension>
28+
</xs:complexContent>
29+
</xs:complexType>
30+
</xs:schema>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<ogr:FeatureCollection
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://ogr.maptools.org/ difference1_b_a.xsd"
5+
xmlns:ogr="http://ogr.maptools.org/"
6+
xmlns:gml="http://www.opengis.net/gml">
7+
<gml:boundedBy>
8+
<gml:Box>
9+
<gml:coord><gml:X>0</gml:X><gml:Y>1</gml:Y></gml:coord>
10+
<gml:coord><gml:X>8</gml:X><gml:Y>9</gml:Y></gml:coord>
11+
</gml:Box>
12+
</gml:boundedBy>
13+
14+
<gml:featureMember>
15+
<ogr:difference1_b_a fid="difference1_b_a.0">
16+
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:3857"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>8,7 8,1 1,1 1,2 7,2 7,7 8,7</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>7,8 7,9 8,9 8,8 7,8</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
17+
<ogr:id_b>B1</ogr:id_b>
18+
</ogr:difference1_b_a>
19+
</gml:featureMember>
20+
<gml:featureMember>
21+
<ogr:difference1_b_a fid="difference1_b_a.1">
22+
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:3857"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>5,3 6,3 6,4 5,4 5,3</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
23+
<ogr:id_b>B4</ogr:id_b>
24+
</ogr:difference1_b_a>
25+
</gml:featureMember>
26+
<gml:featureMember>
27+
<ogr:difference1_b_a fid="difference1_b_a.2">
28+
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:3857"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>1,5 0,5 0,6 1,6 1,5</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>3,5 2,5 2,6 3,6 3,5</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
29+
<ogr:id_b>B2</ogr:id_b>
30+
</ogr:difference1_b_a>
31+
</gml:featureMember>
32+
<gml:featureMember>
33+
<ogr:difference1_b_a fid="difference1_b_a.3">
34+
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:3857"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>5,7 3,7 3,8 5,8 5,7</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
35+
<ogr:id_b>B3</ogr:id_b>
36+
</ogr:difference1_b_a>
37+
</gml:featureMember>
38+
</ogr:FeatureCollection>
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<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">
3+
<xs:import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/2.1.2/feature.xsd"/>
4+
<xs:element name="FeatureCollection" type="ogr:FeatureCollectionType" substitutionGroup="gml:_FeatureCollection"/>
5+
<xs:complexType name="FeatureCollectionType">
6+
<xs:complexContent>
7+
<xs:extension base="gml:AbstractFeatureCollectionType">
8+
<xs:attribute name="lockId" type="xs:string" use="optional"/>
9+
<xs:attribute name="scope" type="xs:string" use="optional"/>
10+
</xs:extension>
11+
</xs:complexContent>
12+
</xs:complexType>
13+
<xs:element name="difference1_b_a" type="ogr:difference1_b_a_Type" substitutionGroup="gml:_Feature"/>
14+
<xs:complexType name="difference1_b_a_Type">
15+
<xs:complexContent>
16+
<xs:extension base="gml:AbstractFeatureType">
17+
<xs:sequence>
18+
<xs:element name="geometryProperty" type="gml:MultiPolygonPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
19+
<xs:element name="id_b" nillable="true" minOccurs="0" maxOccurs="1">
20+
<xs:simpleType>
21+
<xs:restriction base="xs:string">
22+
<xs:maxLength value="255"/>
23+
</xs:restriction>
24+
</xs:simpleType>
25+
</xs:element>
26+
</xs:sequence>
27+
</xs:extension>
28+
</xs:complexContent>
29+
</xs:complexType>
30+
</xs:schema>
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<ogr:FeatureCollection
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://ogr.maptools.org/ symmetrical_difference1_a_b.xsd"
5+
xmlns:ogr="http://ogr.maptools.org/"
6+
xmlns:gml="http://www.opengis.net/gml">
7+
<gml:boundedBy>
8+
<gml:Box>
9+
<gml:coord><gml:X>0</gml:X><gml:Y>1</gml:Y></gml:coord>
10+
<gml:coord><gml:X>9</gml:X><gml:Y>11</gml:Y></gml:coord>
11+
</gml:Box>
12+
</gml:boundedBy>
13+
14+
<gml:featureMember>
15+
<ogr:symmetrical_difference1_a_b fid="symmetrical_difference1_a_b.0">
16+
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:3857"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>2,5 2,3 1,3 1,5 2,5</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>1,6 1,11 8,11 8,10 2,10 2,6 1,6</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
17+
<ogr:id_a>A1</ogr:id_a>
18+
<ogr:id_b xsi:nil="true"/>
19+
</ogr:symmetrical_difference1_a_b>
20+
</gml:featureMember>
21+
<gml:featureMember>
22+
<ogr:symmetrical_difference1_a_b fid="symmetrical_difference1_a_b.1">
23+
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:3857"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>3,3 3,4 4,4 4,3 3,3</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
24+
<ogr:id_a>A4</ogr:id_a>
25+
<ogr:id_b xsi:nil="true"/>
26+
</ogr:symmetrical_difference1_a_b>
27+
</gml:featureMember>
28+
<gml:featureMember>
29+
<ogr:symmetrical_difference1_a_b fid="symmetrical_difference1_a_b.2">
30+
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:3857"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>4,6 6,6 6,5 4,5 4,6</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
31+
<ogr:id_a>A2</ogr:id_a>
32+
<ogr:id_b xsi:nil="true"/>
33+
</ogr:symmetrical_difference1_a_b>
34+
</gml:featureMember>
35+
<gml:featureMember>
36+
<ogr:symmetrical_difference1_a_b fid="symmetrical_difference1_a_b.3">
37+
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:3857"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>7,7 6,7 6,8 7,8 7,7</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>8,8 9,8 9,7 8,7 8,8</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
38+
<ogr:id_a>A3</ogr:id_a>
39+
<ogr:id_b xsi:nil="true"/>
40+
</ogr:symmetrical_difference1_a_b>
41+
</gml:featureMember>
42+
<gml:featureMember>
43+
<ogr:symmetrical_difference1_a_b fid="symmetrical_difference1_a_b.4">
44+
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:3857"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>8,7 8,1 1,1 1,2 7,2 7,7 8,7</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>7,8 7,9 8,9 8,8 7,8</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
45+
<ogr:id_a xsi:nil="true"/>
46+
<ogr:id_b>B1</ogr:id_b>
47+
</ogr:symmetrical_difference1_a_b>
48+
</gml:featureMember>
49+
<gml:featureMember>
50+
<ogr:symmetrical_difference1_a_b fid="symmetrical_difference1_a_b.5">
51+
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:3857"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>5,3 6,3 6,4 5,4 5,3</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
52+
<ogr:id_a xsi:nil="true"/>
53+
<ogr:id_b>B4</ogr:id_b>
54+
</ogr:symmetrical_difference1_a_b>
55+
</gml:featureMember>
56+
<gml:featureMember>
57+
<ogr:symmetrical_difference1_a_b fid="symmetrical_difference1_a_b.6">
58+
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:3857"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>1,5 0,5 0,6 1,6 1,5</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>3,5 2,5 2,6 3,6 3,5</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
59+
<ogr:id_a xsi:nil="true"/>
60+
<ogr:id_b>B2</ogr:id_b>
61+
</ogr:symmetrical_difference1_a_b>
62+
</gml:featureMember>
63+
<gml:featureMember>
64+
<ogr:symmetrical_difference1_a_b fid="symmetrical_difference1_a_b.7">
65+
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:3857"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>5,7 3,7 3,8 5,8 5,7</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
66+
<ogr:id_a xsi:nil="true"/>
67+
<ogr:id_b>B3</ogr:id_b>
68+
</ogr:symmetrical_difference1_a_b>
69+
</gml:featureMember>
70+
</ogr:FeatureCollection>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<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">
3+
<xs:import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/2.1.2/feature.xsd"/>
4+
<xs:element name="FeatureCollection" type="ogr:FeatureCollectionType" substitutionGroup="gml:_FeatureCollection"/>
5+
<xs:complexType name="FeatureCollectionType">
6+
<xs:complexContent>
7+
<xs:extension base="gml:AbstractFeatureCollectionType">
8+
<xs:attribute name="lockId" type="xs:string" use="optional"/>
9+
<xs:attribute name="scope" type="xs:string" use="optional"/>
10+
</xs:extension>
11+
</xs:complexContent>
12+
</xs:complexType>
13+
<xs:element name="symmetrical_difference1_a_b" type="ogr:symmetrical_difference1_a_b_Type" substitutionGroup="gml:_Feature"/>
14+
<xs:complexType name="symmetrical_difference1_a_b_Type">
15+
<xs:complexContent>
16+
<xs:extension base="gml:AbstractFeatureType">
17+
<xs:sequence>
18+
<xs:element name="geometryProperty" type="gml:MultiPolygonPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
19+
<xs:element name="id_a" nillable="true" minOccurs="0" maxOccurs="1">
20+
<xs:simpleType>
21+
<xs:restriction base="xs:string">
22+
<xs:maxLength value="255"/>
23+
</xs:restriction>
24+
</xs:simpleType>
25+
</xs:element>
26+
<xs:element name="id_b" nillable="true" minOccurs="0" maxOccurs="1">
27+
<xs:simpleType>
28+
<xs:restriction base="xs:string">
29+
<xs:maxLength value="255"/>
30+
</xs:restriction>
31+
</xs:simpleType>
32+
</xs:element>
33+
</xs:sequence>
34+
</xs:extension>
35+
</xs:complexContent>
36+
</xs:complexType>
37+
</xs:schema>
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<ogr:FeatureCollection
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://ogr.maptools.org/ symmetrical_difference1_b_a.xsd"
5+
xmlns:ogr="http://ogr.maptools.org/"
6+
xmlns:gml="http://www.opengis.net/gml">
7+
<gml:boundedBy>
8+
<gml:Box>
9+
<gml:coord><gml:X>0</gml:X><gml:Y>1</gml:Y></gml:coord>
10+
<gml:coord><gml:X>9</gml:X><gml:Y>11</gml:Y></gml:coord>
11+
</gml:Box>
12+
</gml:boundedBy>
13+
14+
<gml:featureMember>
15+
<ogr:symmetrical_difference1_b_a fid="symmetrical_difference1_b_a.0">
16+
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:3857"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>8,7 8,1 1,1 1,2 7,2 7,7 8,7</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>7,8 7,9 8,9 8,8 7,8</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
17+
<ogr:id_b>B1</ogr:id_b>
18+
<ogr:id_a xsi:nil="true"/>
19+
</ogr:symmetrical_difference1_b_a>
20+
</gml:featureMember>
21+
<gml:featureMember>
22+
<ogr:symmetrical_difference1_b_a fid="symmetrical_difference1_b_a.1">
23+
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:3857"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>5,3 6,3 6,4 5,4 5,3</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
24+
<ogr:id_b>B4</ogr:id_b>
25+
<ogr:id_a xsi:nil="true"/>
26+
</ogr:symmetrical_difference1_b_a>
27+
</gml:featureMember>
28+
<gml:featureMember>
29+
<ogr:symmetrical_difference1_b_a fid="symmetrical_difference1_b_a.2">
30+
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:3857"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>1,5 0,5 0,6 1,6 1,5</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>3,5 2,5 2,6 3,6 3,5</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
31+
<ogr:id_b>B2</ogr:id_b>
32+
<ogr:id_a xsi:nil="true"/>
33+
</ogr:symmetrical_difference1_b_a>
34+
</gml:featureMember>
35+
<gml:featureMember>
36+
<ogr:symmetrical_difference1_b_a fid="symmetrical_difference1_b_a.3">
37+
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:3857"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>5,7 3,7 3,8 5,8 5,7</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
38+
<ogr:id_b>B3</ogr:id_b>
39+
<ogr:id_a xsi:nil="true"/>
40+
</ogr:symmetrical_difference1_b_a>
41+
</gml:featureMember>
42+
<gml:featureMember>
43+
<ogr:symmetrical_difference1_b_a fid="symmetrical_difference1_b_a.4">
44+
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:3857"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>2,5 2,3 1,3 1,5 2,5</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>1,6 1,11 8,11 8,10 2,10 2,6 1,6</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
45+
<ogr:id_b xsi:nil="true"/>
46+
<ogr:id_a>A1</ogr:id_a>
47+
</ogr:symmetrical_difference1_b_a>
48+
</gml:featureMember>
49+
<gml:featureMember>
50+
<ogr:symmetrical_difference1_b_a fid="symmetrical_difference1_b_a.5">
51+
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:3857"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>3,3 3,4 4,4 4,3 3,3</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
52+
<ogr:id_b xsi:nil="true"/>
53+
<ogr:id_a>A4</ogr:id_a>
54+
</ogr:symmetrical_difference1_b_a>
55+
</gml:featureMember>
56+
<gml:featureMember>
57+
<ogr:symmetrical_difference1_b_a fid="symmetrical_difference1_b_a.6">
58+
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:3857"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>4,6 6,6 6,5 4,5 4,6</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
59+
<ogr:id_b xsi:nil="true"/>
60+
<ogr:id_a>A2</ogr:id_a>
61+
</ogr:symmetrical_difference1_b_a>
62+
</gml:featureMember>
63+
<gml:featureMember>
64+
<ogr:symmetrical_difference1_b_a fid="symmetrical_difference1_b_a.7">
65+
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:3857"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>7,7 6,7 6,8 7,8 7,7</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>8,8 9,8 9,7 8,7 8,8</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
66+
<ogr:id_b xsi:nil="true"/>
67+
<ogr:id_a>A3</ogr:id_a>
68+
</ogr:symmetrical_difference1_b_a>
69+
</gml:featureMember>
70+
</ogr:FeatureCollection>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<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">
3+
<xs:import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/2.1.2/feature.xsd"/>
4+
<xs:element name="FeatureCollection" type="ogr:FeatureCollectionType" substitutionGroup="gml:_FeatureCollection"/>
5+
<xs:complexType name="FeatureCollectionType">
6+
<xs:complexContent>
7+
<xs:extension base="gml:AbstractFeatureCollectionType">
8+
<xs:attribute name="lockId" type="xs:string" use="optional"/>
9+
<xs:attribute name="scope" type="xs:string" use="optional"/>
10+
</xs:extension>
11+
</xs:complexContent>
12+
</xs:complexType>
13+
<xs:element name="symmetrical_difference1_b_a" type="ogr:symmetrical_difference1_b_a_Type" substitutionGroup="gml:_Feature"/>
14+
<xs:complexType name="symmetrical_difference1_b_a_Type">
15+
<xs:complexContent>
16+
<xs:extension base="gml:AbstractFeatureType">
17+
<xs:sequence>
18+
<xs:element name="geometryProperty" type="gml:MultiPolygonPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
19+
<xs:element name="id_b" nillable="true" minOccurs="0" maxOccurs="1">
20+
<xs:simpleType>
21+
<xs:restriction base="xs:string">
22+
<xs:maxLength value="255"/>
23+
</xs:restriction>
24+
</xs:simpleType>
25+
</xs:element>
26+
<xs:element name="id_a" nillable="true" minOccurs="0" maxOccurs="1">
27+
<xs:simpleType>
28+
<xs:restriction base="xs:string">
29+
<xs:maxLength value="255"/>
30+
</xs:restriction>
31+
</xs:simpleType>
32+
</xs:element>
33+
</xs:sequence>
34+
</xs:extension>
35+
</xs:complexContent>
36+
</xs:complexType>
37+
</xs:schema>

‎python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5258,4 +5258,74 @@ tests:
52585258
name: expected/wedge_buffers.gml
52595259
type: vector
52605260

5261+
- algorithm: native:difference
5262+
name: Test Difference A - B (basic)
5263+
params:
5264+
INPUT:
5265+
name: custom/overlay1_a.geojson
5266+
type: vector
5267+
OVERLAY:
5268+
name: custom/overlay1_b.geojson
5269+
type: vector
5270+
results:
5271+
OUTPUT:
5272+
name: expected/difference1_a_b.gml
5273+
type: vector
5274+
pk: id_a
5275+
compare:
5276+
fields:
5277+
fid: skip
5278+
- algorithm: native:difference
5279+
name: Test Difference B - A (basic)
5280+
params:
5281+
INPUT:
5282+
name: custom/overlay1_b.geojson
5283+
type: vector
5284+
OVERLAY:
5285+
name: custom/overlay1_a.geojson
5286+
type: vector
5287+
results:
5288+
OUTPUT:
5289+
name: expected/difference1_b_a.gml
5290+
type: vector
5291+
pk: id_b
5292+
compare:
5293+
fields:
5294+
fid: skip
5295+
5296+
- algorithm: native:symmetricaldifference
5297+
name: Test Symmetrical Difference A - B (basic)
5298+
params:
5299+
INPUT:
5300+
name: custom/overlay1_a.geojson
5301+
type: vector
5302+
OVERLAY:
5303+
name: custom/overlay1_b.geojson
5304+
type: vector
5305+
results:
5306+
OUTPUT:
5307+
name: expected/symmetrical_difference1_a_b.gml
5308+
type: vector
5309+
pk: [id_a, id_b]
5310+
compare:
5311+
fields:
5312+
fid: skip
5313+
- algorithm: native:symmetricaldifference
5314+
name: Test Symmetrical Difference B - A (basic)
5315+
params:
5316+
INPUT:
5317+
name: custom/overlay1_b.geojson
5318+
type: vector
5319+
OVERLAY:
5320+
name: custom/overlay1_a.geojson
5321+
type: vector
5322+
results:
5323+
OUTPUT:
5324+
name: expected/symmetrical_difference1_b_a.gml
5325+
type: vector
5326+
pk: [id_a, id_b]
5327+
compare:
5328+
fields:
5329+
fid: skip
5330+
52615331
# See ../README.md for a description of the file format

‎src/analysis/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ SET(QGIS_ANALYSIS_SRCS
2727
processing/qgsalgorithmcentroid.cpp
2828
processing/qgsalgorithmclip.cpp
2929
processing/qgsalgorithmconvexhull.cpp
30+
processing/qgsalgorithmdifference.cpp
3031
processing/qgsalgorithmdissolve.cpp
3132
processing/qgsalgorithmdropgeometry.cpp
3233
processing/qgsalgorithmdropmzvalues.cpp
@@ -73,13 +74,15 @@ SET(QGIS_ANALYSIS_SRCS
7374
processing/qgsalgorithmstringconcatenation.cpp
7475
processing/qgsalgorithmswapxy.cpp
7576
processing/qgsalgorithmsubdivide.cpp
77+
processing/qgsalgorithmsymmetricaldifference.cpp
7678
processing/qgsalgorithmtransect.cpp
7779
processing/qgsalgorithmtransform.cpp
7880
processing/qgsalgorithmtranslate.cpp
7981
processing/qgsalgorithmuniquevalueindex.cpp
8082
processing/qgsalgorithmwedgebuffers.cpp
8183

8284
processing/qgsnativealgorithms.cpp
85+
processing/qgsoverlayutils.cpp
8386

8487
raster/qgsalignraster.cpp
8588
raster/qgsninecellfilter.cpp
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/***************************************************************************
2+
qgsalgorithmdifference.cpp
3+
---------------------
4+
Date : April 2018
5+
Copyright : (C) 2018 by Martin Dobias
6+
Email : wonder dot sk at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#include "qgsalgorithmdifference.h"
17+
18+
#include "qgsoverlayutils.h"
19+
20+
///@cond PRIVATE
21+
22+
23+
QString QgsDifferenceAlgorithm::name() const
24+
{
25+
return QStringLiteral( "difference" );
26+
}
27+
28+
QString QgsDifferenceAlgorithm::displayName() const
29+
{
30+
return QObject::tr( "Difference" );
31+
}
32+
33+
QString QgsDifferenceAlgorithm::group() const
34+
{
35+
return QObject::tr( "Vector overlay" );
36+
}
37+
38+
QString QgsDifferenceAlgorithm::groupId() const
39+
{
40+
return QStringLiteral( "vectoroverlay" );
41+
}
42+
43+
QString QgsDifferenceAlgorithm::shortHelpString() const
44+
{
45+
return QObject::tr( "This algorithm extracts features from the Input layer that fall outside, or partially overlap, features in the Difference layer. Input layer features that partially overlap the difference layer feature(s) are split along the boundary of the difference layer feature(s) and only the portions outside the difference layer features are retained." )
46+
+ QStringLiteral( "\n\n" )
47+
+ QObject::tr( "Attributes are not modified." );
48+
}
49+
50+
QgsProcessingAlgorithm *QgsDifferenceAlgorithm::createInstance() const
51+
{
52+
return new QgsDifferenceAlgorithm();
53+
}
54+
55+
void QgsDifferenceAlgorithm::initAlgorithm( const QVariantMap & )
56+
{
57+
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
58+
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "OVERLAY" ), QObject::tr( "Difference layer" ) ) );
59+
addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Difference" ) ) );
60+
}
61+
62+
63+
QVariantMap QgsDifferenceAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
64+
{
65+
std::unique_ptr< QgsFeatureSource > sourceA( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
66+
if ( !sourceA )
67+
throw QgsProcessingException( QObject::tr( "Could not load source layer for INPUT" ) );
68+
69+
std::unique_ptr< QgsFeatureSource > sourceB( parameterAsSource( parameters, QStringLiteral( "OVERLAY" ), context ) );
70+
if ( !sourceB )
71+
throw QgsProcessingException( QObject::tr( "Could not load source layer for OVERLAY" ) );
72+
73+
QgsWkbTypes::Type geomType = QgsWkbTypes::multiType( sourceA->wkbType() );
74+
75+
QString dest;
76+
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, sourceA->fields(), geomType, sourceA->sourceCrs() ) );
77+
78+
QVariantMap outputs;
79+
outputs.insert( QStringLiteral( "OUTPUT" ), dest );
80+
81+
int count = 0;
82+
int total = sourceA->featureCount();
83+
QgsOverlayUtils::difference( *sourceA.get(), *sourceB.get(), *sink.get(), context, feedback, count, total, QgsOverlayUtils::OutputA );
84+
85+
return outputs;
86+
}
87+
88+
///@endcond PRIVATE
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/***************************************************************************
2+
qgsalgorithmdifference.h
3+
---------------------
4+
Date : April 2018
5+
Copyright : (C) 2018 by Martin Dobias
6+
Email : wonder dot sk at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#ifndef QGSALGORITHMDIFFERENCE_H
17+
#define QGSALGORITHMDIFFERENCE_H
18+
19+
#define SIP_NO_FILE
20+
21+
#include "qgsprocessingalgorithm.h"
22+
23+
///@cond PRIVATE
24+
25+
class QgsDifferenceAlgorithm : public QgsProcessingAlgorithm
26+
{
27+
public:
28+
QgsDifferenceAlgorithm() = default;
29+
30+
virtual QString name() const override;
31+
virtual QString displayName() const override;
32+
virtual QString group() const override;
33+
virtual QString groupId() const override;
34+
QString shortHelpString() const override;
35+
36+
protected:
37+
virtual QgsProcessingAlgorithm *createInstance() const override;
38+
virtual void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override;
39+
virtual QVariantMap processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
40+
41+
};
42+
43+
///@endcond PRIVATE
44+
45+
#endif // QGSALGORITHMDIFFERENCE_H
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/***************************************************************************
2+
qgsalgorithmsymmetricaldifference.cpp
3+
---------------------
4+
Date : April 2018
5+
Copyright : (C) 2018 by Martin Dobias
6+
Email : wonder dot sk at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#include "qgsalgorithmsymmetricaldifference.h"
17+
18+
#include "qgsoverlayutils.h"
19+
20+
///@cond PRIVATE
21+
22+
QString QgsSymmetricalDifferenceAlgorithm::name() const
23+
{
24+
return QStringLiteral( "symmetricaldifference" );
25+
}
26+
27+
QString QgsSymmetricalDifferenceAlgorithm::displayName() const
28+
{
29+
return QObject::tr( "Symmetrical difference" );
30+
}
31+
32+
QString QgsSymmetricalDifferenceAlgorithm::group() const
33+
{
34+
return QObject::tr( "Vector overlay" );
35+
}
36+
37+
QString QgsSymmetricalDifferenceAlgorithm::groupId() const
38+
{
39+
return QStringLiteral( "vectoroverlay" );
40+
}
41+
42+
QString QgsSymmetricalDifferenceAlgorithm::shortHelpString() const
43+
{
44+
return QObject::tr( "This algorithm creates a layer containing features from both the Input and Difference layers but with the overlapping areas between the two layers removed. The attribute table of the Symmetrical Difference layer contains attributes from both the Input and Difference layers." );
45+
}
46+
47+
QgsProcessingAlgorithm *QgsSymmetricalDifferenceAlgorithm::createInstance() const
48+
{
49+
return new QgsSymmetricalDifferenceAlgorithm();
50+
}
51+
52+
void QgsSymmetricalDifferenceAlgorithm::initAlgorithm( const QVariantMap & )
53+
{
54+
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
55+
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "OVERLAY" ), QObject::tr( "Difference layer" ) ) );
56+
addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Symmetrical difference" ) ) );
57+
}
58+
59+
60+
QVariantMap QgsSymmetricalDifferenceAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
61+
{
62+
std::unique_ptr< QgsFeatureSource > sourceA( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
63+
if ( !sourceA )
64+
throw QgsProcessingException( QObject::tr( "Could not load source layer for INPUT" ) );
65+
66+
std::unique_ptr< QgsFeatureSource > sourceB( parameterAsSource( parameters, QStringLiteral( "OVERLAY" ), context ) );
67+
if ( !sourceB )
68+
throw QgsProcessingException( QObject::tr( "Could not load source layer for OVERLAY" ) );
69+
70+
QgsWkbTypes::Type geomType = QgsWkbTypes::multiType( sourceA->wkbType() );
71+
72+
QgsFields fields = QgsProcessingUtils::combineFields( sourceA->fields(), sourceB->fields() );
73+
74+
QString dest;
75+
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, fields, geomType, sourceA->sourceCrs() ) );
76+
77+
QVariantMap outputs;
78+
outputs.insert( QStringLiteral( "OUTPUT" ), dest );
79+
80+
int count = 0;
81+
int total = sourceA->featureCount() + sourceB->featureCount();
82+
83+
QgsOverlayUtils::difference( *sourceA.get(), *sourceB.get(), *sink.get(), context, feedback, count, total, QgsOverlayUtils::OutputAB );
84+
85+
QgsOverlayUtils::difference( *sourceB.get(), *sourceA.get(), *sink.get(), context, feedback, count, total, QgsOverlayUtils::OutputBA );
86+
87+
return outputs;
88+
}
89+
90+
///@endcond PRIVATE
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/***************************************************************************
2+
qgsalgorithmsymmetricaldifference.h
3+
---------------------
4+
Date : April 2018
5+
Copyright : (C) 2018 by Martin Dobias
6+
Email : wonder dot sk at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#ifndef QGSALGORITHMSYMMETRICALDIFFERENCE_H
17+
#define QGSALGORITHMSYMMETRICALDIFFERENCE_H
18+
19+
#define SIP_NO_FILE
20+
21+
#include "qgsprocessingalgorithm.h"
22+
23+
///@cond PRIVATE
24+
25+
class QgsSymmetricalDifferenceAlgorithm : public QgsProcessingAlgorithm
26+
{
27+
public:
28+
QgsSymmetricalDifferenceAlgorithm() = default;
29+
30+
virtual QString name() const override;
31+
virtual QString displayName() const override;
32+
virtual QString group() const override;
33+
virtual QString groupId() const override;
34+
QString shortHelpString() const override;
35+
36+
protected:
37+
virtual QgsProcessingAlgorithm *createInstance() const override;
38+
virtual void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override;
39+
virtual QVariantMap processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
40+
41+
};
42+
43+
///@endcond PRIVATE
44+
45+
#endif // QGSALGORITHMSYMMETRICALDIFFERENCE_H

‎src/analysis/processing/qgsnativealgorithms.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "qgsalgorithmcentroid.h"
2525
#include "qgsalgorithmclip.h"
2626
#include "qgsalgorithmconvexhull.h"
27+
#include "qgsalgorithmdifference.h"
2728
#include "qgsalgorithmdissolve.h"
2829
#include "qgsalgorithmdropgeometry.h"
2930
#include "qgsalgorithmdropmzvalues.h"
@@ -70,6 +71,7 @@
7071
#include "qgsalgorithmstringconcatenation.h"
7172
#include "qgsalgorithmsubdivide.h"
7273
#include "qgsalgorithmswapxy.h"
74+
#include "qgsalgorithmsymmetricaldifference.h"
7375
#include "qgsalgorithmtransect.h"
7476
#include "qgsalgorithmtransform.h"
7577
#include "qgsalgorithmtranslate.h"
@@ -125,6 +127,7 @@ void QgsNativeAlgorithms::loadAlgorithms()
125127
addAlgorithm( new QgsClipAlgorithm() );
126128
addAlgorithm( new QgsCollectAlgorithm() );
127129
addAlgorithm( new QgsConvexHullAlgorithm() );
130+
addAlgorithm( new QgsDifferenceAlgorithm() );
128131
addAlgorithm( new QgsDissolveAlgorithm() );
129132
addAlgorithm( new QgsDropGeometryAlgorithm() );
130133
addAlgorithm( new QgsDropMZValuesAlgorithm() );
@@ -173,6 +176,7 @@ void QgsNativeAlgorithms::loadAlgorithms()
173176
addAlgorithm( new QgsStringConcatenationAlgorithm() );
174177
addAlgorithm( new QgsSubdivideAlgorithm() );
175178
addAlgorithm( new QgsSwapXYAlgorithm() );
179+
addAlgorithm( new QgsSymmetricalDifferenceAlgorithm() );
176180
addAlgorithm( new QgsTransectAlgorithm() );
177181
addAlgorithm( new QgsTransformAlgorithm() );
178182
addAlgorithm( new QgsTranslateAlgorithm() );
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/***************************************************************************
2+
qgsoverlayutils.cpp
3+
---------------------
4+
Date : April 2018
5+
Copyright : (C) 2018 by Martin Dobias
6+
Email : wonder dot sk at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#include "qgsoverlayutils.h"
17+
18+
#include "qgsgeometryengine.h"
19+
#include "qgsprocessingalgorithm.h"
20+
21+
///@cond PRIVATE
22+
23+
void QgsOverlayUtils::difference( const QgsFeatureSource &sourceA, const QgsFeatureSource &sourceB, QgsFeatureSink &sink, QgsProcessingContext &context, QgsProcessingFeedback *feedback, int &count, int totalCount, QgsOverlayUtils::DifferenceOutput outputAttrs )
24+
{
25+
QgsFeatureRequest requestB;
26+
requestB.setSubsetOfAttributes( QgsAttributeList() );
27+
if ( outputAttrs != OutputBA )
28+
requestB.setDestinationCrs( sourceA.sourceCrs(), context.transformContext() );
29+
QgsSpatialIndex indexB( sourceB.getFeatures( requestB ), feedback );
30+
31+
int fieldsCountA = sourceA.fields().count();
32+
int fieldsCountB = sourceB.fields().count();
33+
QgsAttributes attrs;
34+
attrs.resize( outputAttrs == OutputA ? fieldsCountA : ( fieldsCountA + fieldsCountB ) );
35+
36+
if ( totalCount == 0 )
37+
totalCount = 1; // avoid division by zero
38+
39+
QgsFeature featA;
40+
QgsFeatureRequest requestA;
41+
if ( outputAttrs == OutputBA )
42+
requestA.setDestinationCrs( sourceB.sourceCrs(), context.transformContext() );
43+
QgsFeatureIterator fitA = sourceA.getFeatures( requestA );
44+
while ( fitA.nextFeature( featA ) )
45+
{
46+
if ( feedback->isCanceled() )
47+
break;
48+
49+
if ( featA.hasGeometry() )
50+
{
51+
QgsGeometry geom( featA.geometry() );
52+
QgsFeatureIds intersects = indexB.intersects( geom.boundingBox() ).toSet();
53+
54+
QgsFeatureRequest request;
55+
request.setFilterFids( intersects );
56+
request.setSubsetOfAttributes( QgsAttributeList() );
57+
if ( outputAttrs != OutputBA )
58+
request.setDestinationCrs( sourceA.sourceCrs(), context.transformContext() );
59+
60+
std::unique_ptr< QgsGeometryEngine > engine;
61+
if ( !intersects.isEmpty() )
62+
{
63+
// use prepared geometries for faster intersection tests
64+
engine.reset( QgsGeometry::createGeometryEngine( geom.constGet() ) );
65+
engine->prepareGeometry();
66+
}
67+
68+
QVector<QgsGeometry> geometriesB;
69+
QgsFeature featB;
70+
QgsFeatureIterator fitB = sourceB.getFeatures( request );
71+
while ( fitB.nextFeature( featB ) )
72+
{
73+
if ( feedback->isCanceled() )
74+
break;
75+
76+
if ( engine->intersects( featB.geometry().constGet() ) )
77+
geometriesB << featB.geometry();
78+
}
79+
80+
if ( !geometriesB.isEmpty() )
81+
{
82+
QgsGeometry geomB = QgsGeometry::unaryUnion( geometriesB );
83+
geom = geom.difference( geomB );
84+
}
85+
86+
const QgsAttributes attrsA( featA.attributes() );
87+
switch ( outputAttrs )
88+
{
89+
case OutputA:
90+
attrs = attrsA;
91+
break;
92+
case OutputAB:
93+
for ( int i = 0; i < fieldsCountA; ++i )
94+
attrs[i] = attrsA[i];
95+
break;
96+
case OutputBA:
97+
for ( int i = 0; i < fieldsCountA; ++i )
98+
attrs[i + fieldsCountB] = attrsA[i];
99+
break;
100+
}
101+
102+
QgsFeature outFeat;
103+
outFeat.setGeometry( geom );
104+
outFeat.setAttributes( attrs );
105+
sink.addFeature( outFeat, QgsFeatureSink::FastInsert );
106+
}
107+
else
108+
{
109+
// TODO: should we write out features that do not have geometry?
110+
sink.addFeature( featA, QgsFeatureSink::FastInsert );
111+
}
112+
113+
++count;
114+
feedback->setProgress( count / ( double ) totalCount * 100. );
115+
}
116+
}
117+
118+
///@endcond PRIVATE
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/***************************************************************************
2+
qgsoverlayutils.h
3+
---------------------
4+
Date : April 2018
5+
Copyright : (C) 2018 by Martin Dobias
6+
Email : wonder dot sk at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#ifndef QGSOVERLAYUTILS_H
17+
#define QGSOVERLAYUTILS_H
18+
19+
#define SIP_NO_FILE
20+
21+
///@cond PRIVATE
22+
23+
class QgsFeatureSource;
24+
class QgsFeatureSink;
25+
class QgsProcessingContext;
26+
class QgsProcessingFeedback;
27+
28+
namespace QgsOverlayUtils
29+
{
30+
31+
//! how to write out attributes of features after overlay operation
32+
enum DifferenceOutput
33+
{
34+
OutputA, //!< Write only attributes of the first layer
35+
OutputAB, //!< Write attributes of both layers
36+
OutputBA, //!< Write attributes of both layers, inverted (first attributes of B, then attributes of A)
37+
};
38+
39+
void difference( const QgsFeatureSource &sourceA, const QgsFeatureSource &sourceB, QgsFeatureSink &sink, QgsProcessingContext &context, QgsProcessingFeedback *feedback, int &count, int totalCount, DifferenceOutput outputAttrs );
40+
41+
}
42+
43+
///@endcond PRIVATE
44+
45+
#endif // QGSOVERLAYUTILS_H

0 commit comments

Comments
 (0)
Please sign in to comment.