Skip to content

Commit

Permalink
[FEATURE][processing] New algorithm "Geodesic line split at antimerid…
Browse files Browse the repository at this point in the history
…ian"

Ports the similar algorithm from the shape tools plugin to c++, and utilises
built in QgsDistanceArea ellipsoidal calculations to split the lines.

This algorithm splits a line into multiple geodesic segments, whenever the
line crosses the antimeridian (±180 degrees longitude)

Splitting at the antimeridian helps the visual display of the lines in some
projections. The returned geometry will always be a multi-part geometry.

Whenever line segments in the input geometry cross the antimeridian,
they will be split into two segments, with the latitude of the breakpoint
being determined using a geodesic line connecting the points either side
of this segment. The current project ellipsoid setting will be used when
calculating this breakpoint.

If the input geometry contains M or Z values, these will be linearly
interpolated for the new vertices created at the antimeridian.

Supports in-place edit mode also.
  • Loading branch information
nyalldawson committed Jan 11, 2019
1 parent 021f5ea commit 2a774d6
Show file tree
Hide file tree
Showing 14 changed files with 519 additions and 0 deletions.
@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ogr.maptools.org/ antimeridian_lines.xsd"
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy>
<gml:Box>
<gml:coord><gml:X>-164.6491419175783</gml:X><gml:Y>-58.13530913536049</gml:Y></gml:coord>
<gml:coord><gml:X>158.1643794482545</gml:X><gml:Y>62.51129510894471</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:antimeridian_lines fid="antimeridian_lines.0">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>-80.891554628534,62.5112951089447 -26.2185771128241,-21.706771212382 52.802689984781,39.8338700993836</gml:coordinates></gml:LineString></ogr:geometryProperty>
<ogr:pk>1</ogr:pk>
</ogr:antimeridian_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:antimeridian_lines fid="antimeridian_lines.1">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>107.475667500491,60.0670531623558 106.811623239167,-46.1399448949947 154.180113880308,23.1390106826322 154.180113880308,23.1390106826322</gml:coordinates></gml:LineString></ogr:geometryProperty>
<ogr:pk>2</ogr:pk>
</ogr:antimeridian_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:antimeridian_lines fid="antimeridian_lines.2">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>135.808222650333,55.5956988168508 -150.925560516874,56.4614475462057</gml:coordinates></gml:LineString></ogr:geometryProperty>
<ogr:pk>3</ogr:pk>
</ogr:antimeridian_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:antimeridian_lines fid="antimeridian_lines.3">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>129.831824298413,-56.9474822647808 -150.482864342658,-58.1353091353605</gml:coordinates></gml:LineString></ogr:geometryProperty>
<ogr:pk>4</ogr:pk>
</ogr:antimeridian_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:antimeridian_lines fid="antimeridian_lines.4">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>137.800355434306,-52.6123900774682 147.539671267064,-12.4080274655396 -164.649141917578,54.5823408082887</gml:coordinates></gml:LineString></ogr:geometryProperty>
<ogr:pk>5</ogr:pk>
</ogr:antimeridian_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:antimeridian_lines fid="antimeridian_lines.5">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>143.998101873334,42.0078449653839 158.164379448254,33.2620367778 -154.90982608482,-49.5548177386129 -139.415459987251,28.9038080381852</gml:coordinates></gml:LineString></ogr:geometryProperty>
<ogr:pk>6</ogr:pk>
</ogr:antimeridian_lines>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -0,0 +1,30 @@
<?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="antimeridian_lines" type="ogr:antimeridian_lines_Type" substitutionGroup="gml:_Feature"/>
<xs:complexType name="antimeridian_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="pk" 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,32 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ogr.maptools.org/ antimeridian_multilines.xsd"
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy>
<gml:Box>
<gml:coord><gml:X>-18328658.63781422</gml:X><gml:Y>-7995795.633934054</gml:Y></gml:coord>
<gml:coord><gml:X>17606778.18181374</gml:X><gml:Y>8981409.887731705</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:antimeridian_multilines fid="antimeridian_lines.3">
<ogr:geometryProperty><gml:MultiLineString srsName="EPSG:3857"><gml:lineStringMember><gml:LineString><gml:coordinates>15339865.3980791,-6911619.95475655 16424041.0772565,-1392180.13348932 -18328658.6378142,7281225.29993063</gml:coordinates></gml:LineString></gml:lineStringMember><gml:lineStringMember><gml:LineString><gml:coordinates>15118102.1909746,7478348.15069018 -16800956.5444278,7650830.64510478</gml:coordinates></gml:LineString></gml:lineStringMember><gml:lineStringMember><gml:LineString><gml:coordinates>14452812.5696611,-7749392.07048463 -16751675.831738,-7995795.63393405</gml:coordinates></gml:LineString></gml:lineStringMember></gml:MultiLineString></ogr:geometryProperty>
<ogr:pk>4</ogr:pk>
</ogr:antimeridian_multilines>
</gml:featureMember>
<gml:featureMember>
<ogr:antimeridian_multilines fid="antimeridian_lines.1">
<ogr:geometryProperty><gml:MultiLineString srsName="EPSG:3857"><gml:lineStringMember><gml:LineString><gml:coordinates>-9004806.67072468,8981409.8877317 -2918638.65352375,-2476355.8126668 5877968.56162091,4841830.02178128</gml:coordinates></gml:LineString></gml:lineStringMember><gml:lineStringMember><gml:LineString><gml:coordinates>11964136.5788218,8414681.69179801 11890215.5097871,-5802803.91923412 17163251.7676048,2648838.30708134</gml:coordinates></gml:LineString></gml:lineStringMember></gml:MultiLineString></ogr:geometryProperty>
<ogr:pk>2</ogr:pk>
</ogr:antimeridian_multilines>
</gml:featureMember>
<gml:featureMember>
<ogr:antimeridian_multilines fid="antimeridian_lines.5">
<ogr:geometryProperty><gml:MultiLineString srsName="EPSG:3857"><gml:lineStringMember><gml:LineString><gml:coordinates>16029795.3757375,5162154.65426553 17606778.1818137,3930136.83701837 -17244482.9586367,-6369532.11516781 -15519658.0144908,3363408.64108469</gml:coordinates></gml:LineString></gml:lineStringMember></gml:MultiLineString></ogr:geometryProperty>
<ogr:pk>6</ogr:pk>
</ogr:antimeridian_multilines>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -0,0 +1,30 @@
<?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="antimeridian_multilines" type="ogr:antimeridian_multilines_Type" substitutionGroup="gml:_Feature"/>
<xs:complexType name="antimeridian_multilines_Type">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureType">
<xs:sequence>
<xs:element name="geometryProperty" type="gml:MultiLineStringPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
<xs:element name="pk" 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,50 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ogr.maptools.org/ antimeridian_lines_split.xsd"
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy>
<gml:Box>
<gml:coord><gml:X>-180</gml:X><gml:Y>-63.73125193527754</gml:Y></gml:coord>
<gml:coord><gml:X>180</gml:X><gml:Y>62.5112951089447</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:antimeridian_lines_split fid="antimeridian_lines.0">
<ogr:geometryProperty><gml:MultiLineString srsName="EPSG:4326"><gml:lineStringMember><gml:LineString><gml:coordinates>-80.891554628534,62.5112951089447 -26.2185771128241,-21.706771212382 52.802689984781,39.8338700993836</gml:coordinates></gml:LineString></gml:lineStringMember></gml:MultiLineString></ogr:geometryProperty>
<ogr:pk>1</ogr:pk>
</ogr:antimeridian_lines_split>
</gml:featureMember>
<gml:featureMember>
<ogr:antimeridian_lines_split fid="antimeridian_lines.1">
<ogr:geometryProperty><gml:MultiLineString srsName="EPSG:4326"><gml:lineStringMember><gml:LineString><gml:coordinates>107.475667500491,60.0670531623558 106.811623239167,-46.1399448949947 154.180113880308,23.1390106826322 154.180113880308,23.1390106826322</gml:coordinates></gml:LineString></gml:lineStringMember></gml:MultiLineString></ogr:geometryProperty>
<ogr:pk>2</ogr:pk>
</ogr:antimeridian_lines_split>
</gml:featureMember>
<gml:featureMember>
<ogr:antimeridian_lines_split fid="antimeridian_lines.2">
<ogr:geometryProperty><gml:MultiLineString srsName="EPSG:4326"><gml:lineStringMember><gml:LineString><gml:coordinates>135.808222650333,55.5956988168508 180.0,61.4742159088028</gml:coordinates></gml:LineString></gml:lineStringMember><gml:lineStringMember><gml:LineString><gml:coordinates>-180.0,61.4742159088028 -150.925560516874,56.4614475462057</gml:coordinates></gml:LineString></gml:lineStringMember></gml:MultiLineString></ogr:geometryProperty>
<ogr:pk>3</ogr:pk>
</ogr:antimeridian_lines_split>
</gml:featureMember>
<gml:featureMember>
<ogr:antimeridian_lines_split fid="antimeridian_lines.3">
<ogr:geometryProperty><gml:MultiLineString srsName="EPSG:4326"><gml:lineStringMember><gml:LineString><gml:coordinates>129.831824298413,-56.9474822647808 180.0,-63.7312519352775</gml:coordinates></gml:LineString></gml:lineStringMember><gml:lineStringMember><gml:LineString><gml:coordinates>-180.0,-63.7312519352775 -150.482864342658,-58.1353091353605</gml:coordinates></gml:LineString></gml:lineStringMember></gml:MultiLineString></ogr:geometryProperty>
<ogr:pk>4</ogr:pk>
</ogr:antimeridian_lines_split>
</gml:featureMember>
<gml:featureMember>
<ogr:antimeridian_lines_split fid="antimeridian_lines.4">
<ogr:geometryProperty><gml:MultiLineString srsName="EPSG:4326"><gml:lineStringMember><gml:LineString><gml:coordinates>137.800355434306,-52.6123900774682 147.539671267064,-12.4080274655396 180.0,43.2521377014247</gml:coordinates></gml:LineString></gml:lineStringMember><gml:lineStringMember><gml:LineString><gml:coordinates>-180.0,43.2521377014247 -164.649141917578,54.5823408082887</gml:coordinates></gml:LineString></gml:lineStringMember></gml:MultiLineString></ogr:geometryProperty>
<ogr:pk>5</ogr:pk>
</ogr:antimeridian_lines_split>
</gml:featureMember>
<gml:featureMember>
<ogr:antimeridian_lines_split fid="antimeridian_lines.5">
<ogr:geometryProperty><gml:MultiLineString srsName="EPSG:4326"><gml:lineStringMember><gml:LineString><gml:coordinates>143.998101873334,42.0078449653839 158.164379448254,33.2620367778 180.0,-12.246360544555</gml:coordinates></gml:LineString></gml:lineStringMember><gml:lineStringMember><gml:LineString><gml:coordinates>-180.0,-12.246360544555 -154.90982608482,-49.5548177386129 -139.415459987251,28.9038080381852</gml:coordinates></gml:LineString></gml:lineStringMember></gml:MultiLineString></ogr:geometryProperty>
<ogr:pk>6</ogr:pk>
</ogr:antimeridian_lines_split>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -0,0 +1,30 @@
<?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="antimeridian_lines_split" type="ogr:antimeridian_lines_split_Type" substitutionGroup="gml:_Feature"/>
<xs:complexType name="antimeridian_lines_split_Type">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureType">
<xs:sequence>
<xs:element name="geometryProperty" type="gml:MultiLineStringPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
<xs:element name="pk" 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,32 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ogr.maptools.org/ antimeridian_multilines_split.xsd"
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy>
<gml:Box>
<gml:coord><gml:X>-20037508.34278924</gml:X><gml:Y>-9281844.407529537</gml:Y></gml:coord>
<gml:coord><gml:X>20037508.34278924</gml:X><gml:Y>8981409.887731699</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:antimeridian_multilines_split fid="antimeridian_lines.3">
<ogr:geometryProperty><gml:MultiLineString srsName="EPSG:3857"><gml:lineStringMember><gml:LineString><gml:coordinates>15339865.3980791,-6911619.95475655 16424041.0772565,-1392180.13348932 20037508.3427892,5350428.8616031</gml:coordinates></gml:LineString></gml:lineStringMember><gml:lineStringMember><gml:LineString><gml:coordinates>-20037508.3427892,5350428.8616031 -18328658.6378142,7281225.29993063</gml:coordinates></gml:LineString></gml:lineStringMember><gml:lineStringMember><gml:LineString><gml:coordinates>15118102.1909746,7478348.15069018 20037508.3427892,8735532.58767424</gml:coordinates></gml:LineString></gml:lineStringMember><gml:lineStringMember><gml:LineString><gml:coordinates>-20037508.3427892,8735532.58767424 -16800956.5444278,7650830.64510478</gml:coordinates></gml:LineString></gml:lineStringMember><gml:lineStringMember><gml:LineString><gml:coordinates>14452812.5696611,-7749392.07048463 20037508.3427892,-9281844.40752954</gml:coordinates></gml:LineString></gml:lineStringMember><gml:lineStringMember><gml:LineString><gml:coordinates>-20037508.3427892,-9281844.40752954 -16751675.831738,-7995795.63393405</gml:coordinates></gml:LineString></gml:lineStringMember></gml:MultiLineString></ogr:geometryProperty>
<ogr:pk>4</ogr:pk>
</ogr:antimeridian_multilines_split>
</gml:featureMember>
<gml:featureMember>
<ogr:antimeridian_multilines_split fid="antimeridian_lines.1">
<ogr:geometryProperty><gml:MultiLineString srsName="EPSG:3857"><gml:lineStringMember><gml:LineString><gml:coordinates>-9004806.67072468,8981409.8877317 -2918638.65352375,-2476355.8126668 5877968.56162091,4841830.02178128</gml:coordinates></gml:LineString></gml:lineStringMember><gml:lineStringMember><gml:LineString><gml:coordinates>11964136.5788218,8414681.69179801 11890215.5097871,-5802803.91923412 17163251.7676048,2648838.30708134</gml:coordinates></gml:LineString></gml:lineStringMember></gml:MultiLineString></ogr:geometryProperty>
<ogr:pk>2</ogr:pk>
</ogr:antimeridian_multilines_split>
</gml:featureMember>
<gml:featureMember>
<ogr:antimeridian_multilines_split fid="antimeridian_lines.5">
<ogr:geometryProperty><gml:MultiLineString srsName="EPSG:3857"><gml:lineStringMember><gml:LineString><gml:coordinates>16029795.3757375,5162154.65426553 17606778.1818137,3930136.83701837 20037508.3427892,-1373758.73029182</gml:coordinates></gml:LineString></gml:lineStringMember><gml:lineStringMember><gml:LineString><gml:coordinates>-20037508.3427892,-1373758.73029182 -17244482.9586367,-6369532.11516781 -15519658.0144908,3363408.64108469</gml:coordinates></gml:LineString></gml:lineStringMember></gml:MultiLineString></ogr:geometryProperty>
<ogr:pk>6</ogr:pk>
</ogr:antimeridian_multilines_split>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -0,0 +1,30 @@
<?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="antimeridian_multilines_split" type="ogr:antimeridian_multilines_split_Type" substitutionGroup="gml:_Feature"/>
<xs:complexType name="antimeridian_multilines_split_Type">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureType">
<xs:sequence>
<xs:element name="geometryProperty" type="gml:MultiLineStringPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
<xs:element name="pk" 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 2a774d6

Please sign in to comment.