Skip to content
Permalink
Browse files

[FEATURE][processing] Add new mode to "Join Attributes by Location" a…

…lgorithm

to take attributes from matching feature with largest area of overlap only

This allows for easy polygon->polygon joins, where you expect there to be
only a single matching feature and don't want to include features which
are just touching or have just tiny sliver polygon overlaps.

Sponsored by SMEC/SJ
  • Loading branch information
nyalldawson committed Jan 13, 2020
1 parent 4c495dc commit 771fc3ff604ed97b5e29acf2809c73207246fc75
Showing with 1,502 additions and 67 deletions.
  1. +48 −0 python/plugins/processing/tests/testdata/custom/join_lines_crossing_multiple_lines.gml
  2. +36 −0 python/plugins/processing/tests/testdata/custom/join_lines_crossing_multiple_lines.xsd
  3. +48 −0 python/plugins/processing/tests/testdata/custom/join_lines_crossing_multiple_polygons.gml
  4. +36 −0 python/plugins/processing/tests/testdata/custom/join_lines_crossing_multiple_polygons.xsd
  5. +42 −0 python/plugins/processing/tests/testdata/custom/polygons_crossing_multiple_polygons.gml
  6. +36 −0 python/plugins/processing/tests/testdata/custom/polygons_crossing_multiple_polygons.xsd
  7. +63 −0 python/plugins/processing/tests/testdata/expected/join_lines_to_lines_largest.gml
  8. +55 −0 python/plugins/processing/tests/testdata/expected/join_lines_to_lines_largest.xsd
  9. +68 −0 python/plugins/processing/tests/testdata/expected/join_lines_to_polys_largest.gml
  10. +62 −0 python/plugins/processing/tests/testdata/expected/join_lines_to_polys_largest.xsd
  11. +79 −0 python/plugins/processing/tests/testdata/expected/join_polys_to_lines_largest.gml
  12. +62 −0 python/plugins/processing/tests/testdata/expected/join_polys_to_lines_largest.xsd
  13. +58 −0 python/plugins/processing/tests/testdata/expected/join_polys_to_lines_largest_discard.gml
  14. +62 −0 python/plugins/processing/tests/testdata/expected/join_polys_to_lines_largest_discard.xsd
  15. +58 −0 python/plugins/processing/tests/testdata/expected/join_polys_to_lines_largest_discard_no_join.gml
  16. +62 −0 python/plugins/processing/tests/testdata/expected/join_polys_to_lines_largest_discard_no_join.xsd
  17. +29 −0 python/plugins/processing/tests/testdata/expected/join_polys_to_lines_largest_unjoined.gml
  18. +43 −0 python/plugins/processing/tests/testdata/expected/join_polys_to_lines_largest_unjoined.xsd
  19. +67 −0 python/plugins/processing/tests/testdata/expected/join_polys_to_polys_largest.gml
  20. +49 −0 python/plugins/processing/tests/testdata/expected/join_polys_to_polys_largest.xsd
  21. +116 −0 python/plugins/processing/tests/testdata/qgis_algorithm_tests3.yaml
  22. +313 −64 src/analysis/processing/qgsalgorithmjoinbylocation.cpp
  23. +10 −3 src/analysis/processing/qgsalgorithmjoinbylocation.h
@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ogr.maptools.org/ join_lines_crossing_multiple_lines.xsd"
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy>
<gml:Box>
<gml:coord><gml:X>-2</gml:X><gml:Y>-3</gml:Y></gml:coord>
<gml:coord><gml:X>10</gml:X><gml:Y>8</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:join_lines_crossing_multiple_lines fid="join_lines_crossing_multiple_lines.0">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>-2,7 -2,-3 3,-3</gml:coordinates></gml:LineString></ogr:geometryProperty>
<ogr:name2>line2</ogr:name2>
<ogr:val2>1</ogr:val2>
</ogr:join_lines_crossing_multiple_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:join_lines_crossing_multiple_lines fid="join_lines_crossing_multiple_lines.1">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>5,3 10,3</gml:coordinates></gml:LineString></ogr:geometryProperty>
<ogr:name2>line3</ogr:name2>
<ogr:val2>3</ogr:val2>
</ogr:join_lines_crossing_multiple_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:join_lines_crossing_multiple_lines fid="join_lines_crossing_multiple_lines.2">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>7,8 7,5</gml:coordinates></gml:LineString></ogr:geometryProperty>
<ogr:name2>line4</ogr:name2>
<ogr:val2>4</ogr:val2>
</ogr:join_lines_crossing_multiple_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:join_lines_crossing_multiple_lines fid="join_lines_crossing_multiple_lines.3">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>0,0 6,0</gml:coordinates></gml:LineString></ogr:geometryProperty>
<ogr:name2>line5</ogr:name2>
<ogr:val2>5</ogr:val2>
</ogr:join_lines_crossing_multiple_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:join_lines_crossing_multiple_lines fid="join_lines_crossing_multiple_lines.4">
<ogr:name2>line1</ogr:name2>
<ogr:val2 xsi:nil="true"/>
</ogr:join_lines_crossing_multiple_lines>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -0,0 +1,36 @@
<?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="join_lines_crossing_multiple_lines" type="ogr:join_lines_crossing_multiple_lines_Type" substitutionGroup="gml:_Feature"/>
<xs:complexType name="join_lines_crossing_multiple_lines_Type">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureType">
<xs:sequence>
<xs:element name="geometryProperty" type="gml:LineStringPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
<xs:element name="name2" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:string">
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="val2" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:totalDigits value="10"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ogr.maptools.org/ join_lines_crossing_multiple_polygons.xsd"
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy>
<gml:Box>
<gml:coord><gml:X>-2</gml:X><gml:Y>-3</gml:Y></gml:coord>
<gml:coord><gml:X>10</gml:X><gml:Y>6</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:join_lines_crossing_multiple_polygons fid="join_lines_crossing_multiple_polygons.0">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>1,4 1,0 3,0</gml:coordinates></gml:LineString></ogr:geometryProperty>
<ogr:name>line4</ogr:name>
<ogr:val xsi:nil="true"/>
</ogr:join_lines_crossing_multiple_polygons>
</gml:featureMember>
<gml:featureMember>
<ogr:join_lines_crossing_multiple_polygons fid="join_lines_crossing_multiple_polygons.1">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>4,0 5,0</gml:coordinates></gml:LineString></ogr:geometryProperty>
<ogr:name>line2</ogr:name>
<ogr:val>3</ogr:val>
</ogr:join_lines_crossing_multiple_polygons>
</gml:featureMember>
<gml:featureMember>
<ogr:join_lines_crossing_multiple_polygons fid="join_lines_crossing_multiple_polygons.2">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>1,-3 2,-3</gml:coordinates></gml:LineString></ogr:geometryProperty>
<ogr:name>line3</ogr:name>
<ogr:val>4</ogr:val>
</ogr:join_lines_crossing_multiple_polygons>
</gml:featureMember>
<gml:featureMember>
<ogr:join_lines_crossing_multiple_polygons fid="join_lines_crossing_multiple_polygons.3">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>9,6 -1,5 -2,5 -2,0 10,1</gml:coordinates></gml:LineString></ogr:geometryProperty>
<ogr:name>line1</ogr:name>
<ogr:val>11</ogr:val>
</ogr:join_lines_crossing_multiple_polygons>
</gml:featureMember>
<gml:featureMember>
<ogr:join_lines_crossing_multiple_polygons fid="join_lines_crossing_multiple_polygons.4">
<ogr:name>line5</ogr:name>
<ogr:val>1</ogr:val>
</ogr:join_lines_crossing_multiple_polygons>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -0,0 +1,36 @@
<?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="join_lines_crossing_multiple_polygons" type="ogr:join_lines_crossing_multiple_polygons_Type" substitutionGroup="gml:_Feature"/>
<xs:complexType name="join_lines_crossing_multiple_polygons_Type">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureType">
<xs:sequence>
<xs:element name="geometryProperty" type="gml:LineStringPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
<xs:element name="name" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:string">
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="val" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:totalDigits value="10"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ogr.maptools.org/ polygons_crossing_multiple_polygons.xsd"
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy>
<gml:Box>
<gml:coord><gml:X>-1</gml:X><gml:Y>-2</gml:Y></gml:coord>
<gml:coord><gml:X>13</gml:X><gml:Y>4</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:polygons_crossing_multiple_polygons fid="polygons_crossing_multiple_polygons.0">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>1,4 1,0 3,0 3,4 1,4</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:name>poly1</ogr:name>
<ogr:val>3</ogr:val>
</ogr:polygons_crossing_multiple_polygons>
</gml:featureMember>
<gml:featureMember>
<ogr:polygons_crossing_multiple_polygons fid="polygons_crossing_multiple_polygons.1">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>11,2 13,2 13,4 11,4 11,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:name>poly2</ogr:name>
<ogr:val>54</ogr:val>
</ogr:polygons_crossing_multiple_polygons>
</gml:featureMember>
<gml:featureMember>
<ogr:polygons_crossing_multiple_polygons fid="polygons_crossing_multiple_polygons.2">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>0,2 -1,2 -1,1 0,1 0,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:name>poly3</ogr:name>
<ogr:val>7</ogr:val>
</ogr:polygons_crossing_multiple_polygons>
</gml:featureMember>
<gml:featureMember>
<ogr:polygons_crossing_multiple_polygons fid="polygons_crossing_multiple_polygons.3">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>1,-2 1,0 10,0 10,-2 1,-2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:name>poly4</ogr:name>
<ogr:val>6</ogr:val>
</ogr:polygons_crossing_multiple_polygons>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -0,0 +1,36 @@
<?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="polygons_crossing_multiple_polygons" type="ogr:polygons_crossing_multiple_polygons_Type" substitutionGroup="gml:_Feature"/>
<xs:complexType name="polygons_crossing_multiple_polygons_Type">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureType">
<xs:sequence>
<xs:element name="geometryProperty" type="gml:PolygonPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
<xs:element name="name" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:string">
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="val" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:totalDigits value="10"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ogr.maptools.org/ join_lines_to_lines_largest.xsd"
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy>
<gml:Box>
<gml:coord><gml:X>-2</gml:X><gml:Y>-3</gml:Y></gml:coord>
<gml:coord><gml:X>10</gml:X><gml:Y>8</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:join_lines_to_lines_largest fid="join_lines_crossing_multiple_lines.0">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>-2,7 -2,-3 3,-3</gml:coordinates></gml:LineString></ogr:geometryProperty>
<ogr:name2>line2</ogr:name2>
<ogr:val2>1</ogr:val2>
<ogr:fid_2>join_lines_crossing_multiple_polygons.3</ogr:fid_2>
<ogr:name>line1</ogr:name>
<ogr:val>11</ogr:val>
</ogr:join_lines_to_lines_largest>
</gml:featureMember>
<gml:featureMember>
<ogr:join_lines_to_lines_largest fid="join_lines_crossing_multiple_lines.1">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>5,3 10,3</gml:coordinates></gml:LineString></ogr:geometryProperty>
<ogr:name2>line3</ogr:name2>
<ogr:val2>3</ogr:val2>
<ogr:fid_2 xsi:nil="true"/>
<ogr:name xsi:nil="true"/>
<ogr:val xsi:nil="true"/>
</ogr:join_lines_to_lines_largest>
</gml:featureMember>
<gml:featureMember>
<ogr:join_lines_to_lines_largest fid="join_lines_crossing_multiple_lines.2">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>7,8 7,5</gml:coordinates></gml:LineString></ogr:geometryProperty>
<ogr:name2>line4</ogr:name2>
<ogr:val2>4</ogr:val2>
<ogr:fid_2>join_lines_crossing_multiple_polygons.3</ogr:fid_2>
<ogr:name>line1</ogr:name>
<ogr:val>11</ogr:val>
</ogr:join_lines_to_lines_largest>
</gml:featureMember>
<gml:featureMember>
<ogr:join_lines_to_lines_largest fid="join_lines_crossing_multiple_lines.3">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>0,0 6,0</gml:coordinates></gml:LineString></ogr:geometryProperty>
<ogr:name2>line5</ogr:name2>
<ogr:val2>5</ogr:val2>
<ogr:fid_2>join_lines_crossing_multiple_polygons.0</ogr:fid_2>
<ogr:name>line4</ogr:name>
<ogr:val xsi:nil="true"/>
</ogr:join_lines_to_lines_largest>
</gml:featureMember>
<gml:featureMember>
<ogr:join_lines_to_lines_largest fid="join_lines_crossing_multiple_lines.4">
<ogr:name2>line1</ogr:name2>
<ogr:val2 xsi:nil="true"/>
<ogr:fid_2 xsi:nil="true"/>
<ogr:name xsi:nil="true"/>
<ogr:val xsi:nil="true"/>
</ogr:join_lines_to_lines_largest>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -0,0 +1,55 @@
<?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="join_lines_to_lines_largest" type="ogr:join_lines_to_lines_largest_Type" substitutionGroup="gml:_Feature"/>
<xs:complexType name="join_lines_to_lines_largest_Type">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureType">
<xs:sequence>
<xs:element name="geometryProperty" type="gml:LineStringPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
<xs:element name="name2" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:string">
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="val2" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:totalDigits value="10"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="fid_2" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:string">
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="name" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:string">
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="val" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:totalDigits value="10"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>

0 comments on commit 771fc3f

Please sign in to comment.
You can’t perform that action at this time.