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

2 dimensional coordinates (XY) are converted in 3 dimensions (XYZ) in postgis #23

Open
EdoardoTona opened this issue Jan 27, 2022 · 19 comments

Comments

@EdoardoTona
Copy link

EdoardoTona commented Jan 27, 2022

Hi,
the version 2.1.0 introduced this issue: all XY geometries are stored in postgis as XYZ geometries, with NaN value in Z.

Example: I store POINT(0 0) using Npgsql and NTS.
Using NetTopologySuite.IO.PostGis v2.0.0, postgis' st_ndims returns: 2 and st_astext returns: POINT (0 0)
Using NetTopologySuite.IO.PostGis v2.1.0, postgis' st_ndims returns: 3 and st_astext returns: POINT Z (0 0 -1.#IND)

-1.#IND is a NaN representation in Windows https://stackoverflow.com/a/347940.

I'm using:

  • net6.0 running in Windows (VS 2022)
  • Npgsql.EntityFrameworkCore.PostgreSQL.NetTopologySuite 5.0.7 (and later)
  • PostgreSQL 11.11, compiled by Visual C++ build 1800, 64-bit managed in Azure as Single Server
  • POSTGIS="2.5.1 r17027" [EXTENSION] PGSQL="110" GEOS="3.7.0-CAPI-1.11.0 3.7.1" PROJ="Rel. 4.9.3, 15 August 2016" GDAL="GDAL 2.2.4, released 2018/03/19 GDAL_DATA not found" LIBXML="2.7.8" LIBJSON="0.12" LIBPROTOBUF="1.2.1" RASTER

How to reproduce the issue:

NpgsqlConnection.GlobalTypeMapper.UseNetTopologySuite();
using NpgsqlConnection conn = new(connectionString);

conn.Open();

using (var cmd = new NpgsqlCommand(@"
  CREATE TEMP TABLE test 
  (
    geometry geometry, 
    CONSTRAINT enforce_dims CHECK (st_ndims(geometry) = 2)
  )", conn))
{
  cmd.ExecuteNonQuery();
}

using (var cmd = new NpgsqlCommand("INSERT INTO test (geometry) VALUES (@g)", conn))
{
  cmd.Parameters.AddWithValue("@g", new WKTReader().Read("POINT(0 0)"));
  cmd.ExecuteNonQuery();
}

The above code works in net6.0 with Npgsql.EntityFrameworkCore.PostgreSQL.NetTopologySuite 5.0.5 (using NetTopologySuite.IO.PostGis 2.0.0). Using the next version 5.0.7 (using NetTopologySuite.IO.PostGis 2.1.0) it throws Npgsql.PostgresException with the message 23514: new row for relation "test" violates check constraint "enforce_dims".

The PostGisReader is smart enougth to see the Z coordinate is NaN, returning a 2 dimensional coordinate.

I think the issue has been introduced with the following commit:

ddd394c#diff-b1018343089a37cb228d0c3357039b782d592ad2591204f0d4c6d41089d1ecf8L585

Version 2.1.0 is:
if (sequence.HasZ)
version 2.0.0 was:
if (sequence.HasZ && !double.IsNaN(sequence.GetZ(0)))

@FObermaier
Copy link
Member

The issue arises because WKTReader has IsOldNtsCoordinateSyntaxAllowed set to true by default.
To prevent that use a WKTWriter instantiated like this:

var reader new WKTReader() { IsOldNtsCoordinateSyntaxAllowed = false };

@DGuidi
Copy link

DGuidi commented Feb 1, 2022

see also NTS Issue #567

@roji
Copy link
Contributor

roji commented Feb 3, 2022

@FObermaier do you think Npgsql needs to be changed in any way here?

@FObermaier
Copy link
Member

@roji , a hint to the documentation on how to use the WKTReader in scenarios involving the PostGisReader should be sufficient.
We should consider making IsOldNtsCoordinateSyntaxAllowed = false the default on NTS' side.

@Swoorup
Copy link

Swoorup commented Mar 1, 2022

Given a Geometry type is there a workaround for this?

@FObermaier
Copy link
Member

The workaround is to prevent creating the Geometry with a dimension of 3 when there are only 2 in the first place.
If the creation of the geometry involves WKTReader you should instantiate that using the following code:

var wktRdr = new NetTopologySuite.IO.WKTReader(/* possible NetTopologySuite.NtsGeometryServices instance */) {
    IsOldNtsCoordinateSyntaxAllowed = false
};

@Swoorup
Copy link

Swoorup commented Mar 1, 2022

@FObermaier that works on the reader. But subsequently manipulating the geometry, if using any of the NTS geometry calculations, Buffer, Reduce will set the HasZ on the CoordinateSequence back to true. Should I configure anything on NTS side?

@DGuidi
Copy link

DGuidi commented Mar 1, 2022

@Swoorup can you add a testcase (I mean, a complete example) that reproduces the error?

@Swoorup
Copy link

Swoorup commented Mar 1, 2022

@DGuidi I use other operations as well but even a buffer(0.0) causes an issue.

let rec hasZ (p: Geometry) =
  match p with
  | :? Point as pp -> pp.CoordinateSequence.HasZ
  | :? Polygon as pp -> pp.ExteriorRing.CoordinateSequence.HasZ
  | :? LineString as ls -> ls.CoordinateSequence.HasZ
  | :? GeometryCollection as gc -> hasZ (gc.GetGeometryN(0))
  | _ -> failwith "Unexpected"

let geom = WKTReader(IsOldNtsCoordinateSyntaxAllowed = false).Read("POINT (0 0)")
let fixed = geom.Buffer(0.0) // removing this line makes `hasZ` false

printfn $"%A{hasZ fixed}"

@DGuidi
Copy link

DGuidi commented Mar 1, 2022

HasZ is true for empty geometries, otherwise it works as expected

var reader = new WKTReader()
{
	IsOldNtsCoordinateSyntaxAllowed = false
};
var geom = (Point)reader.Read("POINT (0 0)");
Assert.IsFalse(geom.CoordinateSequence.HasZ);
var empty = (Polygon)geom.Buffer(0.0);
Assert.IsTrue(empty.IsEmpty);
Assert.IsTrue(empty.ExteriorRing.CoordinateSequence.HasZ);
var poly = (Polygon)geom.Buffer(10.0);
Assert.IsFalse(poly.IsEmpty);
Assert.IsFalse(poly.ExteriorRing.CoordinateSequence.HasZ);

@Swoorup
Copy link

Swoorup commented Mar 1, 2022

@DGuidi It fails for this wkt:

Details
SRID=4283;MULTIPOLYGON(((138.4012 -35.638,138.3996 -35.6404,138.3802 -35.6389,138.3732 -35.6397,138.3678 -35.6423,138.3547 -35.6398,138.2847 -35.6389,138.2651 -35.6413,138.258 -35.6482,138.254 -35.6503,138.2529 -35.6493,138.2474 -35.6539,138.2448 -35.6532,138.2434 -35.6554,138.2403 -35.6545,138.232 -35.6597,138.227 -35.6607,138.2264 -35.6594,138.2208 -35.6624,138.2159 -35.661,138.2066 -35.664,138.2004 -35.6631,138.1948 -35.6653,138.1928 -35.6642,138.185 -35.6649,138.1793 -35.6625,138.1767 -35.6638,138.1714 -35.6607,138.1626 -35.6608,138.1562 -35.6582,138.1549 -35.6544,138.149 -35.655,138.1439 -35.6526,138.1424 -35.6494,138.1356 -35.6472,138.1358 -35.6453,138.1309 -35.6463,138.1274 -35.6445,138.1251 -35.6409,138.1179 -35.6377,138.1147 -35.6328,138.1065 -35.633,138.1 -35.6296,138.0949 -35.6238,138.0957 -35.6162,138.0946 -35.6155,138.0958 -35.6138,138.0935 -35.6024,138.0952 -35.5997,138.1055 -35.5949,138.1115 -35.5872,138.1147 -35.5816,138.1141 -35.5783,138.1199 -35.5693,138.1196 -35.5667,138.1212 -35.5659,138.1226 -35.5611,138.1271 -35.5569,138.1263 -35.5558,138.1505 -35.5364,138.151 -35.5331,138.1578 -35.5302,138.1639 -35.5234,138.165 -35.5197,138.1686 -35.5183,138.1769 -35.5196,138.1884 -35.524,138.2121 -35.5134,138.2149 -35.5111,138.2143 -35.5099,138.218 -35.5113,138.2241 -35.5098,138.2378 -35.5021,138.2442 -35.5013,138.2484 -35.4963,138.2604 -35.4904,138.2766 -35.4782,138.2754 -35.4817,138.2806 -35.4739,138.2919 -35.47,138.29 -35.4695,138.2941 -35.4674,138.295 -35.4641,138.2975 -35.4625,138.3034 -35.4503,138.3185 -35.4287,138.3229 -35.4194,138.3257 -35.4173,138.3279 -35.4092,138.3414 -35.3928,138.3591 -35.3827,138.3624 -35.3781,138.3658 -35.378,138.3809 -35.371,138.3861 -35.3723,138.3932 -35.3677,138.4103 -35.3661,138.4305 -35.3533,138.4398 -35.3513,138.4424 -35.3452,138.4409 -35.3435,138.4458 -35.3368,138.447 -35.3193,138.4437 -35.2903,138.4416 -35.2849,138.4409 -35.2858,138.4391 -35.284,138.4401 -35.2827,138.4419 -35.2834,138.4423 -35.2812,138.4393 -35.2764,138.4401 -35.2691,138.4428 -35.2677,138.4521 -35.2678,138.4603 -35.2602,138.4609 -35.2478,138.4817 -35.2463,138.4609 -35.2471,138.4611 -35.245,138.4672 -35.2449,138.4695 -35.2406,138.4692 -35.2283,138.4672 -35.2215,138.4797 -35.2203,138.4677 -35.2211,138.4668 -35.2185,138.4705 -35.2118,138.4688 -35.194,138.4903 -35.1907,138.5158 -35.1894,138.5147 -35.1748,138.5204 -35.1732,138.52 -35.1688,138.5301 -35.1683,138.5296 -35.1654,138.5345 -35.1636,138.5356 -35.1612,138.5477 -35.1641,138.5522 -35.1588,138.5571 -35.1615,138.5651 -35.1615,138.5661 -35.1585,138.5727 -35.1574,138.5794 -35.1606,138.5797 -35.1559,138.5824 -35.1559,138.5834 -35.152,138.5868 -35.1524,138.5886 -35.1498,138.586 -35.1479,138.5866 -35.1466,138.5957 -35.1451,138.6026 -35.15,138.6056 -35.148,138.6115 -35.1501,138.6182 -35.1577,138.6234 -35.1585,138.6264 -35.1619,138.6319 -35.1638,138.6295 -35.1649,138.6264 -35.1703,138.6175 -35.1763,138.6177 -35.1794,138.6243 -35.1837,138.6342 -35.1832,138.6379 -35.1758,138.6379 -35.1664,138.7188 -35.1664,138.7188 -35.2414,138.7218 -35.2414,138.7206 -35.2427,138.7272 -35.2465,138.7249 -35.2529,138.7221 -35.2542,138.7486 -35.2564,138.7491 -35.253,138.7438 -35.2516,138.7451 -35.2511,138.7459 -35.2453,138.7462 -35.2298,138.7516 -35.2224,138.7567 -35.2203,138.7536 -35.2136,138.7581 -35.2107,138.7659 -35.2114,138.7662 -35.209,138.7754 -35.2099,138.774 -35.2197,138.7723 -35.2222,138.7738 -35.2214,138.7772 -35.2263,138.7851 -35.2286,138.7814 -35.2356,138.7733 -35.2442,138.7728 -35.2471,138.7817 -35.248,138.7836 -35.2504,138.7891 -35.2512,138.7917 -35.2494,138.7936 -35.2526,138.7989 -35.253,138.7972 -35.2505,138.8069 -35.246,138.7997 -35.2454,138.8008 -35.2366,138.8071 -35.239,138.8079 -35.2326,138.812 -35.2297,138.8213 -35.2278,138.8301 -35.2286,138.84 -35.2176,138.8426 -35.2178,138.8401 -35.2146,138.8411 -35.2068,138.8471 -35.2069,138.8481 -35.2042,138.8568 -35.2052,138.8607 -35.2023,138.8596 -35.2016,138.8652 -35.1953,138.8677 -35.1967,138.8692 -35.192,138.872 -35.1899,138.8757 -35.1918,138.8774 -35.1969,138.8842 -35.1938,138.8872 -35.1983,138.8917 -35.1963,138.892 -35.2023,138.8981 -35.1966,138.9035 -35.1942,138.9104 -35.1936,138.9127 -35.2049,138.9201 -35.2086,138.9374 -35.2354,138.9385 -35.2348,138.9433 -35.2411,138.9505 -35.2352,138.9552 -35.2403,138.9892 -35.2262,138.9891 -35.228,138.9919 -35.2304,138.9911 -35.2314,138.9972 -35.2292,139.0035 -35.2412,139.0153 -35.237,139.0232 -35.2523,139.0368 -35.2474,139.0422 -35.2576,139.0947 -35.2575,139.0962 -35.237,139.1115 -35.2341,139.1583 -35.2535,139.1552 -35.3029,139.1521 -35.3039,139.1551 -35.3045,139.1522 -35.353,139.161 -35.3559,139.1583 -35.3578,139.1564 -35.3561,139.1579 -35.3605,139.1551 -35.3635,139.1565 -35.3637,139.1521 -35.366,139.1508 -35.3736,139.1567 -35.3729,139.1436 -35.3763,139.1354 -35.3753,139.1315 -35.3766,139.1349 -35.3765,139.1323 -35.3774,139.1297 -35.3767,139.1098 -35.3821,139.1069 -35.3815,139.1081 -35.382,139.1007 -35.3831,139.1022 -35.3837,139.1012 -35.3849,139.0925 -35.3887,139.0954 -35.387,139.0913 -35.3859,139.089 -35.3884,139.0842 -35.3877,139.0839 -35.3891,139.0765 -35.391,139.0613 -35.3901,139.0356 -35.3917,139.0345 -35.3912,139.0396 -35.3897,139.0285 -35.3906,139.0197 -35.3924,139.0184 -35.3954,139.0132 -35.397,139.0091 -35.3974,139.0081 -35.3952,139.006 -35.3954,139.0007 -35.3987,138.9986 -35.3976,138.993 -35.3985,138.9929 -35.3996,138.9904 -35.3993,138.9914 -35.4004,138.9845 -35.4014,138.9768 -35.4054,138.9773 -35.4067,138.972 -35.4114,138.9732 -35.4143,138.9701 -35.4174,138.9707 -35.4201,138.9662 -35.426,138.9663 -35.4308,138.9655 -35.4285,138.9604 -35.4358,138.9596 -35.4413,138.9575 -35.4423,138.9587 -35.4432,138.9561 -35.444,138.9514 -35.4501,138.9518 -35.4529,138.9547 -35.4556,138.9647 -35.4541,138.9577 -35.4567,138.9549 -35.4606,138.9552 -35.4655,138.9584 -35.4677,138.9578 -35.4735,138.9734 -35.4813,138.9748 -35.4836,138.9809 -35.4819,138.9824 -35.4856,138.9881 -35.4901,138.9991 -35.4885,139.0058 -35.4852,139.0117 -35.4874,139.0121 -35.4898,139.015 -35.492,139.0208 -35.4928,139.0258 -35.4955,139.0275 -35.4944,139.0315 -35.4962,139.0389 -35.4961,139.0476 -35.5018,139.0319 -35.5138,139.0229 -35.5131,139.0163 -35.5155,139.0032 -35.5137,138.9913 -35.5166,138.9892 -35.52,138.981 -35.5182,138.966 -35.5288,138.9663 -35.5413,138.963 -35.5454,138.943 -35.5558,138.9351 -35.5558,138.9315 -35.5624,138.9261 -35.5589,138.9177 -35.5612,138.9077 -35.5564,138.9 -35.5552,138.8989 -35.5507,138.8941 -35.5494,138.8883 -35.5522,138.8881 -35.5554,138.8751 -35.5578,138.8246 -35.5395,138.7731 -35.5242,138.7461 -35.5182,138.7099 -35.5141,138.7005 -35.5182,138.6931 -35.5235,138.6926 -35.5265,138.6957 -35.5272,138.6954 -35.5289,138.6904 -35.5339,138.6883 -35.5327,138.6851 -35.5337,138.6843 -35.5383,138.6789 -35.5367,138.6635 -35.5366,138.6269 -35.5443,138.6323 -35.5443,138.6256 -35.5508,138.6263 -35.5583,138.6192 -35.5579,138.6132 -35.5621,138.6133 -35.5656,138.6097 -35.5702,138.5983 -35.581,138.5993 -35.5826,138.598 -35.5855,138.5992 -35.5845,138.6027 -35.5888,138.6056 -35.5889,138.6057 -35.5927,138.6026 -35.5948,138.5998 -35.5925,138.5844 -35.5993,138.582 -35.6015,138.5822 -35.6055,138.5747 -35.606,138.5651 -35.609,138.5593 -35.6137,138.5556 -35.6193,138.5222 -35.6431,138.5078 -35.637,138.5061 -35.6379,138.5046 -35.6361,138.4945 -35.634,138.4926 -35.6349,138.4924 -35.6334,138.4868 -35.6342,138.4874 -35.6328,138.4834 -35.6334,138.483 -35.6322,138.4792 -35.6348,138.4628 -35.6302,138.4566 -35.6326,138.4491 -35.63,138.4399 -35.631,138.4312 -35.6292,138.421 -35.6335,138.4125 -35.6399,138.4037 -35.6403,138.4012 -35.638)),((138.4903 -35.1907,138.4688 -35.194,138.4665 -35.188,138.4676 -35.1875,138.4649 -35.1846,138.4665 -35.1844,138.467 -35.1821,138.4659 -35.1777,138.4764 -35.1773,138.4766 -35.1809,138.4895 -35.1804,138.4903 -35.1907)))

Another operation that causes it to have Z dimension (just NaNs):

let fixed = GeometrySnapper.SnapToSelf(geometry, 0.0002, true)

@DGuidi
Copy link

DGuidi commented Mar 1, 2022

nope, it works. at least with latest main.

var reader = new WKTReader()
{
IsOldNtsCoordinateSyntaxAllowed = false
};
const string wkt = "MULTIPOLYGON(((138.4012 -35.638,138.3996 -35.6404,138.3802 -35.6389,138.3732 -35.6397,138.3678 -35.6423,138.3547 -35.6398,138.2847 -35.6389,138.2651 -35.6413,138.258 -35.6482,138.254 -35.6503,138.2529 -35.6493,138.2474 -35.6539,138.2448 -35.6532,138.2434 -35.6554,138.2403 -35.6545,138.232 -35.6597,138.227 -35.6607,138.2264 -35.6594,138.2208 -35.6624,138.2159 -35.661,138.2066 -35.664,138.2004 -35.6631,138.1948 -35.6653,138.1928 -35.6642,138.185 -35.6649,138.1793 -35.6625,138.1767 -35.6638,138.1714 -35.6607,138.1626 -35.6608,138.1562 -35.6582,138.1549 -35.6544,138.149 -35.655,138.1439 -35.6526,138.1424 -35.6494,138.1356 -35.6472,138.1358 -35.6453,138.1309 -35.6463,138.1274 -35.6445,138.1251 -35.6409,138.1179 -35.6377,138.1147 -35.6328,138.1065 -35.633,138.1 -35.6296,138.0949 -35.6238,138.0957 -35.6162,138.0946 -35.6155,138.0958 -35.6138,138.0935 -35.6024,138.0952 -35.5997,138.1055 -35.5949,138.1115 -35.5872,138.1147 -35.5816,138.1141 -35.5783,138.1199 -35.5693,138.1196 -35.5667,138.1212 -35.5659,138.1226 -35.5611,138.1271 -35.5569,138.1263 -35.5558,138.1505 -35.5364,138.151 -35.5331,138.1578 -35.5302,138.1639 -35.5234,138.165 -35.5197,138.1686 -35.5183,138.1769 -35.5196,138.1884 -35.524,138.2121 -35.5134,138.2149 -35.5111,138.2143 -35.5099,138.218 -35.5113,138.2241 -35.5098,138.2378 -35.5021,138.2442 -35.5013,138.2484 -35.4963,138.2604 -35.4904,138.2766 -35.4782,138.2754 -35.4817,138.2806 -35.4739,138.2919 -35.47,138.29 -35.4695,138.2941 -35.4674,138.295 -35.4641,138.2975 -35.4625,138.3034 -35.4503,138.3185 -35.4287,138.3229 -35.4194,138.3257 -35.4173,138.3279 -35.4092,138.3414 -35.3928,138.3591 -35.3827,138.3624 -35.3781,138.3658 -35.378,138.3809 -35.371,138.3861 -35.3723,138.3932 -35.3677,138.4103 -35.3661,138.4305 -35.3533,138.4398 -35.3513,138.4424 -35.3452,138.4409 -35.3435,138.4458 -35.3368,138.447 -35.3193,138.4437 -35.2903,138.4416 -35.2849,138.4409 -35.2858,138.4391 -35.284,138.4401 -35.2827,138.4419 -35.2834,138.4423 -35.2812,138.4393 -35.2764,138.4401 -35.2691,138.4428 -35.2677,138.4521 -35.2678,138.4603 -35.2602,138.4609 -35.2478,138.4817 -35.2463,138.4609 -35.2471,138.4611 -35.245,138.4672 -35.2449,138.4695 -35.2406,138.4692 -35.2283,138.4672 -35.2215,138.4797 -35.2203,138.4677 -35.2211,138.4668 -35.2185,138.4705 -35.2118,138.4688 -35.194,138.4903 -35.1907,138.5158 -35.1894,138.5147 -35.1748,138.5204 -35.1732,138.52 -35.1688,138.5301 -35.1683,138.5296 -35.1654,138.5345 -35.1636,138.5356 -35.1612,138.5477 -35.1641,138.5522 -35.1588,138.5571 -35.1615,138.5651 -35.1615,138.5661 -35.1585,138.5727 -35.1574,138.5794 -35.1606,138.5797 -35.1559,138.5824 -35.1559,138.5834 -35.152,138.5868 -35.1524,138.5886 -35.1498,138.586 -35.1479,138.5866 -35.1466,138.5957 -35.1451,138.6026 -35.15,138.6056 -35.148,138.6115 -35.1501,138.6182 -35.1577,138.6234 -35.1585,138.6264 -35.1619,138.6319 -35.1638,138.6295 -35.1649,138.6264 -35.1703,138.6175 -35.1763,138.6177 -35.1794,138.6243 -35.1837,138.6342 -35.1832,138.6379 -35.1758,138.6379 -35.1664,138.7188 -35.1664,138.7188 -35.2414,138.7218 -35.2414,138.7206 -35.2427,138.7272 -35.2465,138.7249 -35.2529,138.7221 -35.2542,138.7486 -35.2564,138.7491 -35.253,138.7438 -35.2516,138.7451 -35.2511,138.7459 -35.2453,138.7462 -35.2298,138.7516 -35.2224,138.7567 -35.2203,138.7536 -35.2136,138.7581 -35.2107,138.7659 -35.2114,138.7662 -35.209,138.7754 -35.2099,138.774 -35.2197,138.7723 -35.2222,138.7738 -35.2214,138.7772 -35.2263,138.7851 -35.2286,138.7814 -35.2356,138.7733 -35.2442,138.7728 -35.2471,138.7817 -35.248,138.7836 -35.2504,138.7891 -35.2512,138.7917 -35.2494,138.7936 -35.2526,138.7989 -35.253,138.7972 -35.2505,138.8069 -35.246,138.7997 -35.2454,138.8008 -35.2366,138.8071 -35.239,138.8079 -35.2326,138.812 -35.2297,138.8213 -35.2278,138.8301 -35.2286,138.84 -35.2176,138.8426 -35.2178,138.8401 -35.2146,138.8411 -35.2068,138.8471 -35.2069,138.8481 -35.2042,138.8568 -35.2052,138.8607 -35.2023,138.8596 -35.2016,138.8652 -35.1953,138.8677 -35.1967,138.8692 -35.192,138.872 -35.1899,138.8757 -35.1918,138.8774 -35.1969,138.8842 -35.1938,138.8872 -35.1983,138.8917 -35.1963,138.892 -35.2023,138.8981 -35.1966,138.9035 -35.1942,138.9104 -35.1936,138.9127 -35.2049,138.9201 -35.2086,138.9374 -35.2354,138.9385 -35.2348,138.9433 -35.2411,138.9505 -35.2352,138.9552 -35.2403,138.9892 -35.2262,138.9891 -35.228,138.9919 -35.2304,138.9911 -35.2314,138.9972 -35.2292,139.0035 -35.2412,139.0153 -35.237,139.0232 -35.2523,139.0368 -35.2474,139.0422 -35.2576,139.0947 -35.2575,139.0962 -35.237,139.1115 -35.2341,139.1583 -35.2535,139.1552 -35.3029,139.1521 -35.3039,139.1551 -35.3045,139.1522 -35.353,139.161 -35.3559,139.1583 -35.3578,139.1564 -35.3561,139.1579 -35.3605,139.1551 -35.3635,139.1565 -35.3637,139.1521 -35.366,139.1508 -35.3736,139.1567 -35.3729,139.1436 -35.3763,139.1354 -35.3753,139.1315 -35.3766,139.1349 -35.3765,139.1323 -35.3774,139.1297 -35.3767,139.1098 -35.3821,139.1069 -35.3815,139.1081 -35.382,139.1007 -35.3831,139.1022 -35.3837,139.1012 -35.3849,139.0925 -35.3887,139.0954 -35.387,139.0913 -35.3859,139.089 -35.3884,139.0842 -35.3877,139.0839 -35.3891,139.0765 -35.391,139.0613 -35.3901,139.0356 -35.3917,139.0345 -35.3912,139.0396 -35.3897,139.0285 -35.3906,139.0197 -35.3924,139.0184 -35.3954,139.0132 -35.397,139.0091 -35.3974,139.0081 -35.3952,139.006 -35.3954,139.0007 -35.3987,138.9986 -35.3976,138.993 -35.3985,138.9929 -35.3996,138.9904 -35.3993,138.9914 -35.4004,138.9845 -35.4014,138.9768 -35.4054,138.9773 -35.4067,138.972 -35.4114,138.9732 -35.4143,138.9701 -35.4174,138.9707 -35.4201,138.9662 -35.426,138.9663 -35.4308,138.9655 -35.4285,138.9604 -35.4358,138.9596 -35.4413,138.9575 -35.4423,138.9587 -35.4432,138.9561 -35.444,138.9514 -35.4501,138.9518 -35.4529,138.9547 -35.4556,138.9647 -35.4541,138.9577 -35.4567,138.9549 -35.4606,138.9552 -35.4655,138.9584 -35.4677,138.9578 -35.4735,138.9734 -35.4813,138.9748 -35.4836,138.9809 -35.4819,138.9824 -35.4856,138.9881 -35.4901,138.9991 -35.4885,139.0058 -35.4852,139.0117 -35.4874,139.0121 -35.4898,139.015 -35.492,139.0208 -35.4928,139.0258 -35.4955,139.0275 -35.4944,139.0315 -35.4962,139.0389 -35.4961,139.0476 -35.5018,139.0319 -35.5138,139.0229 -35.5131,139.0163 -35.5155,139.0032 -35.5137,138.9913 -35.5166,138.9892 -35.52,138.981 -35.5182,138.966 -35.5288,138.9663 -35.5413,138.963 -35.5454,138.943 -35.5558,138.9351 -35.5558,138.9315 -35.5624,138.9261 -35.5589,138.9177 -35.5612,138.9077 -35.5564,138.9 -35.5552,138.8989 -35.5507,138.8941 -35.5494,138.8883 -35.5522,138.8881 -35.5554,138.8751 -35.5578,138.8246 -35.5395,138.7731 -35.5242,138.7461 -35.5182,138.7099 -35.5141,138.7005 -35.5182,138.6931 -35.5235,138.6926 -35.5265,138.6957 -35.5272,138.6954 -35.5289,138.6904 -35.5339,138.6883 -35.5327,138.6851 -35.5337,138.6843 -35.5383,138.6789 -35.5367,138.6635 -35.5366,138.6269 -35.5443,138.6323 -35.5443,138.6256 -35.5508,138.6263 -35.5583,138.6192 -35.5579,138.6132 -35.5621,138.6133 -35.5656,138.6097 -35.5702,138.5983 -35.581,138.5993 -35.5826,138.598 -35.5855,138.5992 -35.5845,138.6027 -35.5888,138.6056 -35.5889,138.6057 -35.5927,138.6026 -35.5948,138.5998 -35.5925,138.5844 -35.5993,138.582 -35.6015,138.5822 -35.6055,138.5747 -35.606,138.5651 -35.609,138.5593 -35.6137,138.5556 -35.6193,138.5222 -35.6431,138.5078 -35.637,138.5061 -35.6379,138.5046 -35.6361,138.4945 -35.634,138.4926 -35.6349,138.4924 -35.6334,138.4868 -35.6342,138.4874 -35.6328,138.4834 -35.6334,138.483 -35.6322,138.4792 -35.6348,138.4628 -35.6302,138.4566 -35.6326,138.4491 -35.63,138.4399 -35.631,138.4312 -35.6292,138.421 -35.6335,138.4125 -35.6399,138.4037 -35.6403,138.4012 -35.638)),((138.4903 -35.1907,138.4688 -35.194,138.4665 -35.188,138.4676 -35.1875,138.4649 -35.1846,138.4665 -35.1844,138.467 -35.1821,138.4659 -35.1777,138.4764 -35.1773,138.4766 -35.1809,138.4895 -35.1804,138.4903 -35.1907)))";
var geom = (Polygon)reader.Read(wkt).GetGeometryN(0);
Assert.IsFalse(geom.ExteriorRing.CoordinateSequence.HasZ);
var buff0 = (Polygon)geom.Buffer(0.0);
Assert.IsFalse(buff0.IsEmpty);
Assert.IsFalse(buff0.ExteriorRing.CoordinateSequence.HasZ);
var buff10 = (Polygon)geom.Buffer(10.0);
Assert.IsFalse(buff10.IsEmpty);
Assert.IsFalse(buff10.ExteriorRing.CoordinateSequence.HasZ);

@FObermaier
Copy link
Member

FObermaier commented Mar 1, 2022

Ahh, I forgot about that....

As a workaround (namespace imports are missing):

  • use latest myget prerelease package
  • use sth. like (namespace imports are missing)
public class ChangeDimensionUtility
{
    private static CoordinateSequence ChangeToXY(CoordinateSequence sequence, Geometry geometry)
    {
        if ((sequence?.Dimension ?? 2) == 2)
            return sequence;

        var res = geometry.Factory.CoordinateSequenceFactory.Create(sequence.Count, 2, 0);
        CoordinateSequences.Copy(sequence, 0, res, 0, sequence.Count);

        return res;
    }

    private static CoordinateSequence ChangeToXYZ(CoordinateSequence sequence, Geometry geometry)
    {
        if ((sequence?.Dimension ?? 3) == 3 && (sequence?.Measures ?? 0) == 0)
            return sequence;

        var res = geometry.Factory.CoordinateSequenceFactory.Create(sequence.Count, 3, 0);
        CoordinateSequences.Copy(sequence, 0, res, 0, sequence.Count);

        return res;
    }

    private static CoordinateSequence ChangeToXYM(CoordinateSequence sequence, Geometry geometry)
    {
        if ((sequence?.Dimension ?? 3) == 3 && (sequence?.Measures ?? 1) == 1)
            return sequence;

        var res = geometry.Factory.CoordinateSequenceFactory.Create(sequence.Count, 3, 1);
        CoordinateSequences.Copy(sequence, 0, res, 0, sequence.Count);

        return res;
    }
    public static CoordinateSequence ChangeToXYZM(CoordinateSequence sequence, Geometry geometry)
    {
        if ((sequence?.Dimension ?? 4) == 4 && (sequence?.Measures ?? 1) == 1)
            return sequence;

        var res = geometry.Factory.CoordinateSequenceFactory.Create(sequence.Count, 4, 1);
        CoordinateSequences.Copy(sequence, 0, res, 0, sequence.Count);

        return res;
    }

    public static T ChangeDimension<T>(T geometry, Ordinates ordinates) where T: Geometry
    {
        if (geometry == null)
            return null;

        Func<CoordinateSequence, Geometry, CoordinateSequence> fn = null;
        switch (ordinates)
        {
            case Ordinates.XY:
                fn = ChangeToXY;
                break;
            case Ordinates.XYZ:
                fn = ChangeToXYZ;
                break;
            case Ordinates.XYM:
                fn = ChangeToXYM;
                break;
            case Ordinates.XYZM:
                fn = ChangeToXYZM;
                break;
            default:
                throw new ArgumentOutOfRangeException(nameof(ordinates));
        }

        var ge = new GeometryEditor(geometry.Factory) { CopyUserData = true };
        var op = new GeometryEditor.CoordinateSequenceOperation(fn);
        return (T)ge.Edit(geometry, op);
    }
}

@Swoorup
Copy link

Swoorup commented Mar 1, 2022

Ahh, I forgot about that....

As a workaround (namespace imports are missing):

Wonder if the easiest fix in the future would be to revert those lines, i.e also check for NaN in the PostGisWriter?

@ketchup201
Copy link

ketchup201 commented Sep 27, 2023

I believe that I'm seeing the same behavior, Creating a polygon like this:

var coords = (new Coordinate[]
{
    new Coordinate(0, 0),
    new Coordinate(80.283745, 0),
    new Coordinate(80.283745, 80.283745),
    new Coordinate(50.5678, 80.283745),
    new Coordinate(0, 0)
});        

var poly = gf.CreatePolygon(coords);
Console.WriteLine(poly.ToString());

Outputs the following:

POLYGON((0 0,80.283745 0,80.283745 80.283745,50.5678 80.283745,0 0))

But subsequently INSERTING it into a database creates a column with the following:

POLYGON M ((0 0 NaN,80.283745 0 NaN,80.283745 80.283745 NaN,50.5678 80.283745 NaN,0 0 NaN))

I've worked around it by doing the following:

var coords = gf.CoordinateSequenceFactory.Create(5, 2, 0);
coords.SetX(0, 0);
coords.SetY(0, 0);

coords.SetX(1, 80.283745);
coords.SetY(1, 0);

coords.SetX(2, 80.283745);
coords.SetY(2, 80.283745);

coords.SetX(3, 50.5678);
coords.SetY(3, 80.283745);

coords.SetX(4, 0);
coords.SetY(4, 0);

var poly = gf.CreatePolygon(coords);

but that seems very awkward.

This is with version 7.0.6. Any chance on this being addressed?

@EdoardoTona
Copy link
Author

As workaround I forced the usage of NetTopologySuite.IO.PostGis 2.0.0

    <PackageReference Include="NetTopologySuite.IO.PostGis" Version="2.0.0">
      <NoWarn>NU1605</NoWarn>
    </PackageReference>

@NinoFloris
Copy link

@FObermaier I'm one of the Npgsql maintainers. We're using PostGisReader and PostGisWriter to implement our serialization. How would we prevent these NaNs from ending up in the database?

@FObermaier
Copy link
Member

FObermaier commented Mar 14, 2024

@NinoFloris are you able to set PostGisWriter's HandleOrdinates property according to the geometry type in that table?

I'm not able to reproduce any of the alledgedly not working examples in this thread.
Before I dig any further into this I'd like to see a PR with a unit test that fails.

@NinoFloris
Copy link

At most we know the datatypename that a user wants to send a db parameter as.

We do expose some config options for the NTS plugin https://github.com/npgsql/npgsql/blob/e8f20a0f74c26dd59b2e02e2bf1889afc231246d/src/Npgsql.NetTopologySuite/NpgsqlNetTopologySuiteExtensions.cs#L23. It seems like that might be too coarse if users have multiple columns with different needs though.

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

7 participants