Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[Python/OGR] Geometry Conversion GML -> WKT -> GML returns invalid Geometry #9238

Closed
kraftto opened this issue Feb 16, 2024 · 12 comments
Closed

Comments

@kraftto
Copy link

kraftto commented Feb 16, 2024

Expected behavior and actual behavior.

Loading the GML 3.2 Geometry mentioned below as WKT and subsequently re-exporting it to GML 3.2 leads to a changed and invalid geometry in terms of XML schema validation. Apparently a gml:Ring or gml:LinearRing element is missing as a gml:interior sub-element, as well as gml:id generation for sub-geometries

Steps to reproduce the problem.

geom = ogr.CreateGeometryFromGML("""
      <gml:Polygon gml:id="Gml_A8808148-445E-4C2A-8E80-6166A5E40DEF" srsName="EPSG:25832">
          <gml:exterior>
            <gml:LinearRing>
              <gml:posList srsName="EPSG:25832">567462.07 5937698.959 567446.882 5937692.583
                567390.995 5937669.124
                567386.293 5937667.145 567389.479 5937654.684 567404.151 5937595.479
                567474.996 5937628.152 567465.27 5937684.42 567462.07 5937698.959
              </gml:posList>
            </gml:LinearRing>
          </gml:exterior>
          <gml:interior>
            <gml:Ring>
              <gml:curveMember>
                <gml:Curve gml:id="Gml_E32F862A-03A3-4631-AC97-AACC25AADB0A" srsName="EPSG:25832">
                  <gml:segments>
                    <gml:Arc interpolation="circularArc3Points" numArc="1">
                      <gml:posList srsName="EPSG:25832">567410.377 5937607.7 567407.834857796
                        5937607.72206805 567406.223 5937609.688
                      </gml:posList>
                    </gml:Arc>
                  </gml:segments>
                </gml:Curve>
              </gml:curveMember>
              <gml:curveMember>
                <gml:LineString gml:id="Gml_9BCFDC9E-A2D0-4244-A05A-8AFBFA8F0912"
                  srsName="EPSG:25832">
                  <gml:posList srsName="EPSG:25832">567406.223 5937609.688 567403.316 5937621.126 </gml:posList>
                </gml:LineString>
              </gml:curveMember>
              <gml:curveMember>
                <gml:LineString gml:id="Gml_CDA688A0-BC60-4F41-A570-3B65C368E3B6"
                  srsName="EPSG:25832">
                  <gml:posList srsName="EPSG:25832">567403.316 5937621.126 567394.606 5937655.401 </gml:posList>
                </gml:LineString>
              </gml:curveMember>
              <gml:curveMember>
                <gml:LineString gml:id="Gml_1CF8947E-9984-4D04-89D7-6EB4C3D8F49C"
                  srsName="EPSG:25832">
                  <gml:posList srsName="EPSG:25832">567394.606 5937655.401 567393.37 5937660.265 </gml:posList>
                </gml:LineString>
              </gml:curveMember>
              <gml:curveMember>
                <gml:LineString gml:id="Gml_6B4A2C69-BD29-47D3-B66B-8EFE543D581C"
                  srsName="EPSG:25832">
                  <gml:posList srsName="EPSG:25832">567393.37 5937660.265 567395.687 5937664.07 </gml:posList>
                </gml:LineString>
              </gml:curveMember>
              <gml:curveMember>
                <gml:LineString gml:id="Gml_196D241D-91EC-4E67-98C7-448A3BAF125D"
                  srsName="EPSG:25832">
                  <gml:posList srsName="EPSG:25832">567395.687 5937664.07 567403 5937667.139 </gml:posList>
                </gml:LineString>
              </gml:curveMember>
              <gml:curveMember>
                <gml:LineString gml:id="Gml_660CFB40-A45A-471C-AC9A-0EE3644E24EA"
                  srsName="EPSG:25832">
                  <gml:posList srsName="EPSG:25832">567403 5937667.139 567415.353 5937672.325 </gml:posList>
                </gml:LineString>
              </gml:curveMember>
              <gml:curveMember>
                <gml:LineString gml:id="Gml_28BCD624-D53C-4D5F-859B-8C8FBE9D7C65"
                  srsName="EPSG:25832">
                  <gml:posList srsName="EPSG:25832">567415.353 5937672.325 567433.538 5937679.955 </gml:posList>
                </gml:LineString>
              </gml:curveMember>
              <gml:curveMember>
                <gml:LineString gml:id="Gml_09464C74-0B61-407B-AC76-997FE51C042D"
                  srsName="EPSG:25832">
                  <gml:posList srsName="EPSG:25832">567433.538 5937679.955 567432.779 5937681.762 </gml:posList>
                </gml:LineString>
              </gml:curveMember>
              <gml:curveMember>
                <gml:LineString gml:id="Gml_87C4F666-9456-4342-A812-6DA363B5BAFB"
                  srsName="EPSG:25832">
                  <gml:posList srsName="EPSG:25832">567432.779 5937681.762 567443.507 5937686.264 </gml:posList>
                </gml:LineString>
              </gml:curveMember>
              <gml:curveMember>
                <gml:LineString gml:id="Gml_B3FECA0C-C1D2-4E2F-8635-00C00347E7A6"
                  srsName="EPSG:25832">
                  <gml:posList srsName="EPSG:25832">567443.507 5937686.264 567445.762 5937685.099 </gml:posList>
                </gml:LineString>
              </gml:curveMember>
              <gml:curveMember>
                <gml:LineString gml:id="Gml_4B3C2606-13D0-464C-A0D6-A8659D8162E9"
                  srsName="EPSG:25832">
                  <gml:posList srsName="EPSG:25832">567445.762 5937685.099 567448.434 5937683.72 </gml:posList>
                </gml:LineString>
              </gml:curveMember>
              <gml:curveMember>
                <gml:LineString gml:id="Gml_8ABE2BFE-0476-40B1-AB14-6697311163D5"
                  srsName="EPSG:25832">
                  <gml:posList srsName="EPSG:25832">567448.434 5937683.72 567451.021 5937668.836 </gml:posList>
                </gml:LineString>
              </gml:curveMember>
              <gml:curveMember>
                <gml:LineString gml:id="Gml_99689F37-6FBC-4DDF-9ABD-F38006182DD5"
                  srsName="EPSG:25832">
                  <gml:posList srsName="EPSG:25832">567451.021 5937668.836 567450.952 5937668.824 </gml:posList>
                </gml:LineString>
              </gml:curveMember>
              <gml:curveMember>
                <gml:LineString gml:id="Gml_FBC55882-5DB1-4749-A17E-FB75E6BD08F2"
                  srsName="EPSG:25832">
                  <gml:posList srsName="EPSG:25832">567450.952 5937668.824 567452.176 5937661.63 </gml:posList>
                </gml:LineString>
              </gml:curveMember>
              <gml:curveMember>
                <gml:LineString gml:id="Gml_CD5CE215-530C-4689-AF9E-78648710F385"
                  srsName="EPSG:25832">
                  <gml:posList srsName="EPSG:25832">567452.176 5937661.63 567453.455 5937654.108 </gml:posList>
                </gml:LineString>
              </gml:curveMember>
              <gml:curveMember>
                <gml:LineString gml:id="Gml_C196321D-9027-4C5D-9585-083638247543"
                  srsName="EPSG:25832">
                  <gml:posList srsName="EPSG:25832">567453.455 5937654.108 567442.758 5937634.17 </gml:posList>
                </gml:LineString>
              </gml:curveMember>
              <gml:curveMember>
                <gml:LineString gml:id="Gml_C4504559-EE9F-44A5-883A-7869326C0805"
                  srsName="EPSG:25832">
                  <gml:posList srsName="EPSG:25832">567442.758 5937634.17 567434.477 5937618.73 </gml:posList>
                </gml:LineString>
              </gml:curveMember>
              <gml:curveMember>
                <gml:LineString gml:id="Gml_557AB784-BE34-4046-83AB-93EF31531FE3"
                  srsName="EPSG:25832">
                  <gml:posList srsName="EPSG:25832">567434.477 5937618.73 567428.223 5937615.867 </gml:posList>
                </gml:LineString>
              </gml:curveMember>
              <gml:curveMember>
                <gml:LineString gml:id="Gml_A633F708-D325-4E4C-B894-3F63253F533D"
                  srsName="EPSG:25832">
                  <gml:posList srsName="EPSG:25832">567428.223 5937615.867 567410.377 5937607.7 </gml:posList>
                </gml:LineString>
              </gml:curveMember>
            </gml:Ring>
          </gml:interior>
        </gml:Polygon>
""")
geom = geom.ExportToWkt()
geom = ogr.CreateGeometryFromWkt(geom)
geom.ExportToGML(options=[ "FORMAT=GML32", f"GMLID=GML_{uuid4()}",  "GML3_LONGSRS=NO", NAMESPACE_DECL=YES"])
                                ]

returns

        <gml:Polygon srsName="EPSG:25832" gml:id="GML_6648ab00-b1e4-4136-a531-bed0561089c9">
          <gml:exterior>
            <gml:LinearRing>
              <gml:posList>567462.07 5937698.959 567446.882 5937692.583 567390.995 5937669.124 567386.293 5937667.145 567389.479 5937654.684 567404.151 5937595.479 567474.996 5937628.152 567465.27 5937684.42 567462.07 5937698.959</gml:posList>
            </gml:LinearRing>
          </gml:exterior>
          <gml:interior>
            <gml:CompositeCurve>
              <gml:curveMember>
                <gml:Curve>
                  <gml:segments>
                    <gml:ArcString>
                      <gml:posList>567410.377 5937607.7 567407.834857796 5937607.72206805 567406.223 5937609.688</gml:posList>
                    </gml:ArcString>
                  </gml:segments>
                </gml:Curve>
              </gml:curveMember>
              <gml:curveMember>
                <gml:Curve>
                  <gml:segments>
                    <gml:LineStringSegment>
                      <gml:posList>567406.223 5937609.688 567403.316 5937621.126</gml:posList>
                    </gml:LineStringSegment>
                  </gml:segments>
                </gml:Curve>
              </gml:curveMember>
              <gml:curveMember>
                <gml:Curve>
                  <gml:segments>
                    <gml:LineStringSegment>
                      <gml:posList>567403.316 5937621.126 567394.606 5937655.401</gml:posList>
                    </gml:LineStringSegment>
                  </gml:segments>
                </gml:Curve>
              </gml:curveMember>
              <gml:curveMember>
                <gml:Curve>
                  <gml:segments>
                    <gml:LineStringSegment>
                      <gml:posList>567394.606 5937655.401 567393.37 5937660.265</gml:posList>
                    </gml:LineStringSegment>
                  </gml:segments>
                </gml:Curve>
              </gml:curveMember>
              <gml:curveMember>
                <gml:Curve>
                  <gml:segments>
                    <gml:LineStringSegment>
                      <gml:posList>567393.37 5937660.265 567395.687 5937664.07</gml:posList>
                    </gml:LineStringSegment>
                  </gml:segments>
                </gml:Curve>
              </gml:curveMember>
              <gml:curveMember>
                <gml:Curve>
                  <gml:segments>
                    <gml:LineStringSegment>
                      <gml:posList>567395.687 5937664.07 567403.0 5937667.139</gml:posList>
                    </gml:LineStringSegment>
                  </gml:segments>
                </gml:Curve>
              </gml:curveMember>
              <gml:curveMember>
                <gml:Curve>
                  <gml:segments>
                    <gml:LineStringSegment>
                      <gml:posList>567403.0 5937667.139 567415.353 5937672.325</gml:posList>
                    </gml:LineStringSegment>
                  </gml:segments>
                </gml:Curve>
              </gml:curveMember>
              <gml:curveMember>
                <gml:Curve>
                  <gml:segments>
                    <gml:LineStringSegment>
                      <gml:posList>567415.353 5937672.325 567433.538 5937679.955</gml:posList>
                    </gml:LineStringSegment>
                  </gml:segments>
                </gml:Curve>
              </gml:curveMember>
              <gml:curveMember>
                <gml:Curve>
                  <gml:segments>
                    <gml:LineStringSegment>
                      <gml:posList>567433.538 5937679.955 567432.779 5937681.762</gml:posList>
                    </gml:LineStringSegment>
                  </gml:segments>
                </gml:Curve>
              </gml:curveMember>
              <gml:curveMember>
                <gml:Curve>
                  <gml:segments>
                    <gml:LineStringSegment>
                      <gml:posList>567432.779 5937681.762 567443.507 5937686.264</gml:posList>
                    </gml:LineStringSegment>
                  </gml:segments>
                </gml:Curve>
              </gml:curveMember>
              <gml:curveMember>
                <gml:Curve>
                  <gml:segments>
                    <gml:LineStringSegment>
                      <gml:posList>567443.507 5937686.264 567445.762 5937685.099</gml:posList>
                    </gml:LineStringSegment>
                  </gml:segments>
                </gml:Curve>
              </gml:curveMember>
              <gml:curveMember>
                <gml:Curve>
                  <gml:segments>
                    <gml:LineStringSegment>
                      <gml:posList>567445.762 5937685.099 567448.434 5937683.72</gml:posList>
                    </gml:LineStringSegment>
                  </gml:segments>
                </gml:Curve>
              </gml:curveMember>
              <gml:curveMember>
                <gml:Curve>
                  <gml:segments>
                    <gml:LineStringSegment>
                      <gml:posList>567448.434 5937683.72 567451.021 5937668.836</gml:posList>
                    </gml:LineStringSegment>
                  </gml:segments>
                </gml:Curve>
              </gml:curveMember>
              <gml:curveMember>
                <gml:Curve>
                  <gml:segments>
                    <gml:LineStringSegment>
                      <gml:posList>567451.021 5937668.836 567450.952 5937668.824</gml:posList>
                    </gml:LineStringSegment>
                  </gml:segments>
                </gml:Curve>
              </gml:curveMember>
              <gml:curveMember>
                <gml:Curve>
                  <gml:segments>
                    <gml:LineStringSegment>
                      <gml:posList>567450.952 5937668.824 567452.176 5937661.63</gml:posList>
                    </gml:LineStringSegment>
                  </gml:segments>
                </gml:Curve>
              </gml:curveMember>
              <gml:curveMember>
                <gml:Curve>
                  <gml:segments>
                    <gml:LineStringSegment>
                      <gml:posList>567452.176 5937661.63 567453.455 5937654.108</gml:posList>
                    </gml:LineStringSegment>
                  </gml:segments>
                </gml:Curve>
              </gml:curveMember>
              <gml:curveMember>
                <gml:Curve>
                  <gml:segments>
                    <gml:LineStringSegment>
                      <gml:posList>567453.455 5937654.108 567442.758 5937634.17</gml:posList>
                    </gml:LineStringSegment>
                  </gml:segments>
                </gml:Curve>
              </gml:curveMember>
              <gml:curveMember>
                <gml:Curve>
                  <gml:segments>
                    <gml:LineStringSegment>
                      <gml:posList>567442.758 5937634.17 567434.477 5937618.73</gml:posList>
                    </gml:LineStringSegment>
                  </gml:segments>
                </gml:Curve>
              </gml:curveMember>
              <gml:curveMember>
                <gml:Curve>
                  <gml:segments>
                    <gml:LineStringSegment>
                      <gml:posList>567434.477 5937618.73 567428.223 5937615.867</gml:posList>
                    </gml:LineStringSegment>
                  </gml:segments>
                </gml:Curve>
              </gml:curveMember>
              <gml:curveMember>
                <gml:Curve>
                  <gml:segments>
                    <gml:LineStringSegment>
                      <gml:posList>567428.223 5937615.867 567410.377 5937607.7</gml:posList>
                    </gml:LineStringSegment>
                  </gml:segments>
                </gml:Curve>
              </gml:curveMember>
            </gml:CompositeCurve>
          </gml:interior>
        </gml:Polygon>

Operating system

Ubuntu 22.04 64 bit

GDAL version and provenance

GDAL 3.4.1 with Python 3.10

@jratike80
Copy link
Collaborator

jratike80 commented Feb 16, 2024

Would you mind attaching the gml as GML file that can be studied with ogrinfo and ogr2ogr?
I wonder if it is too much to trust that things like <gml:Arc interpolation="circularArc3Points" numArc="1"> convert nicely into WKT.

@kraftto
Copy link
Author

kraftto commented Feb 16, 2024

Sure: test1.zip
I'm aware that Arcs won't be converted 1:1, but the resulting geometry should imho be valid nevertheless.

@jratike80
Copy link
Collaborator

jratike80 commented Feb 16, 2024

GDAL seems to find the following WKT. PostGIS says that the geometry is valid and it looks the same in QGIS as the source GML.

image

CURVEPOLYGON ((567462.07 5937698.959,567446.882 5937692.583,567390.995 5937669.124,567386.293 5937667.145,567389.479 5937654.684,567404.151 5937595.479,567474.996 5937628.152,567465.27 5937684.42,567462.07 5937698.959),COMPOUNDCURVE (CIRCULARSTRING (567410.377 5937607.7,567407.834857796 5937607.72206805,567406.223 5937609.688),(567406.223 5937609.688,567403.316 5937621.126),(567403.316 5937621.126,567394.606 5937655.401),(567394.606 5937655.401,567393.37 5937660.265),(567393.37 5937660.265,567395.687 5937664.07),(567395.687 5937664.07,567403.0 5937667.139),(567403.0 5937667.139,567415.353 5937672.325),(567415.353 5937672.325,567433.538 5937679.955),(567433.538 5937679.955,567432.779 5937681.762),(567432.779 5937681.762,567443.507 5937686.264),(567443.507 5937686.264,567445.762 5937685.099),(567445.762 5937685.099,567448.434 5937683.72),(567448.434 5937683.72,567451.021 5937668.836),(567451.021 5937668.836,567450.952 5937668.824),(567450.952 5937668.824,567452.176 5937661.63),(567452.176 5937661.63,567453.455 5937654.108),(567453.455 5937654.108,567442.758 5937634.17),(567442.758 5937634.17,567434.477 5937618.73),(567434.477 5937618.73,567428.223 5937615.867),(567428.223 5937615.867,567410.377 5937607.7)))

Now I wonder how I could convert the WKT into GML3 with the GDAL command line tools because I have only those in my toolbox.

So I made PostGIS to read the WKT

ogr2ogr -f GML gdalgml32.gml PG:"host=localhost port=5432 dbname=db user=user password=pw" -sql "select st_geomfromtext('CURVEPOLYGON...

The resulting gml can be opened with QGIS and the geometry looks the same than before. I had to delete the .gfs file first but maybe it remained from some earlier experiment.

gdalgml32.zip

I do not know how valid my tests are and what they prove, if anything.

@kraftto
Copy link
Author

kraftto commented Feb 17, 2024

gdalgml32.zip has the gml:Ring element as well as the gml:id attribute on sub-geometries and seems to be valid:

          <gml:interior>
            <gml:Ring>
              <gml:curveMember>
                <gml:Curve gml:id="gmltest.geom.0.interior.0.0">

The WKT string seems to be the same in both cases (geom.ExportToWkt() and st_geomfromtext('CURVEPOLYGON...), the resulting GML geometry, however, differs with geom.ExportToGML().

On a side note, I get an error when using ST_AsGML inside the DB on the geometry: SQL Error [XX000]: FEHLER: lwgeom_to_gml2: 'CompoundCurve' geometry type not supported I just realized that the default GML version for this function is 2. So ST_AsGML(3, geom) results in an apparently valid GML geometry with

          <gml:interior>
            <gml:Ring>

albeit no gml:id, but these aren't mandatory for GML 3.2.2.

@zoidable
Copy link

@pathmapper maybe have a look

@jratike80
Copy link
Collaborator

Please notice that in my test the curvepolygon WKT was first turned into a PostGIS geometry by the PostGIS database with -sql "select st_geomfromtext('CURVEPOLYGON... while in the original case GDAL did the conversion into GDAL geometry with geom = ogr.CreateGeometryFromWkt(geom).

So the next step might be to test if GDAL could have some bug in CreateGeometryFromWkt by checking the content of geom and is it somehow different than the one that comes through PostGIS. I paste the geometry from the PostGIS ST_GeomFromText if it happens to help someone.

010A000000020000000102000000090000003D0AD7234C512141894160BD88A65641068195C32D5121413BDF4F2587A65641D7A370FDBD502141B29DEF4781A6564193180496B450214114AE47C980A65641EE7C3FF5BA502141F0A7C6AB7DA656413BDF4F4DD85021419EEFA7DE6EA6564146B6F3FD65512141355EBA0977A65641A4703D8A52512141AE47E11A85A656413D0AD7234C512141894160BD88A65641010900000014000000010800000003000000DD2406C1E4502141CDCCCCEC71A65641257B72ABDF502141E95C36EE71A65641560E2D72DC5021412731086C72A65641010200000002000000560E2D72DC5021412731086C72A6564183C0CAA1D65021414E62104875A6564101020000000200000083C0CAA1D65021414E62104875A65641CBA14536C5502141E7FBA9D97DA65641010200000002000000CBA14536C5502141E7FBA9D97DA65641D7A370BDC25021418FC2F5107FA65641010200000002000000D7A370BDC25021418FC2F5107FA65641C976BE5FC750214148E17A0480A65641010200000002000000C976BE5FC750214148E17A0480A6564100000000D65021414260E5C880A6564101020000000200000000000000D65021414260E5C880A656417F6ABCB4EE502141CDCCCC1482A656410102000000020000007F6ABCB4EE502141CDCCCC1482A656416ABC74131351214152B81EFD83A656410102000000020000006ABC74131351214152B81EFD83A656418716D98E11512141A69BC47084A656410102000000020000008716D98E11512141A69BC47084A6564106819503275121414260E59085A6564101020000000200000006819503275121414260E59085A656412FDD24862B5121411904564685A656410102000000020000002FDD24862B5121411904564685A656417D3F35DE30512141E17A14EE84A656410102000000020000007D3F35DE30512141E17A14EE84A656411283C00A365121412506813581A656410102000000020000001283C00A365121412506813581A65641448B6CE7355121417F6ABC3481A65641010200000002000000448B6CE7355121417F6ABC3481A6564108AC1C5A3851214185EB51687FA6564101020000000200000008AC1C5A3851214185EB51687FA656418FC2F5E83A512141D578E9867DA656410102000000020000008FC2F5E83A512141D578E9867DA656417593188425512141AE47E18A78A656410102000000020000007593188425512141AE47E18A78A65641105839F414512141EC51B8AE74A65641010200000002000000105839F414512141EC51B8AE74A65641560E2D720851214191ED7CF773A65641010200000002000000560E2D720851214191ED7CF773A65641DD2406C1E4502141CDCCCCEC71A65641

@pathmapper
Copy link
Contributor

pathmapper commented Feb 17, 2024

With GDAL 3.9.0dev-d7aed6e0b0, released 2024/02/09 (debug build) and the original approach in #9238 (comment) there is a valid geometry as result:

out_geometry.zip (created not with recent GDAL)

@pathmapper
Copy link
Contributor

pathmapper commented Feb 17, 2024

@kraftto maybe the issue is that your result is missing the namespace declaration?

If xmlns:gml="http://www.opengis.net/gml/3.2" is added to the Polygon element of your result and the GML is opened via drag'n'drop in QGIS it loads just fine and passes validity checks with the Check validity tool (QGIS and GEOS).

@pathmapper
Copy link
Contributor

OK, I see now why you are saying the result is invalid :-)

image

@kraftto
Copy link
Author

kraftto commented Feb 17, 2024

Yeah I should have mentioned that I'm talking about XML Schema validity :) I added this to the original issue description. The GML geometry should look like the one in gdalgml32.zip.

@pathmapper
Copy link
Contributor

Turns out that this has been reported before in #7294 and was fixed in #7296.

You need minimum GDAL 3.6.3 and then you will get

<gml:interior>
    <gml:Ring>
        <gml:curveMember>

From https://github.com/OSGeo/gdal/blob/v3.6.3/NEWS.md

GML driver:
fix CurvePolygon export of CompoundCurve and CircularString child elements (#7294)

@kraftto
Copy link
Author

kraftto commented Feb 17, 2024

My bad! Similar use case in #7294 I guess ;)

@kraftto kraftto closed this as completed Feb 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants