NetTopologySuite / NetTopologySuite.IO.ShapeFile

The ShapeFile IO module for NTS.
33 stars 25 forks source link

Wip/redo everything #69

Open KubaSzostak opened 3 years ago

KubaSzostak commented 3 years ago

There are two parts of library. NetTopologySuite.IO.Esri.Core and NetTopologySuite.IO.Esri. The former provides forward-only readers and writers for Esri shapefiles. It is vanilla .NET Standard 2.0 library without any dependencies. The latter is is full featured NTS library. It provides unified access to shapefile triplet (SHP, SHX, DBF) through wrapping Core classes.

Writing features to a shapefile

var features = new List<Feature>();
for (int i = 1; i < 5; i++)
{
    var attributes = new AttributesTable();
    attributes.Add("date", new DateTime(2000, 1, i + 1));
    attributes.Add("float", i * 0.1);
    attributes.Add("int", i);
    attributes.Add("logical", i % 2 == 0);
    attributes.Add("text", i.ToString("0.00"));

    var lineCoords = new List<CoordinateZ>();
    lineCoords.Add(new CoordinateZ(i, i + 1, i));
    lineCoords.Add(new CoordinateZ(i, i, i));
    lineCoords.Add(new CoordinateZ(i + 1, i, i));
    var line = new LineString(lineCoords.ToArray());

    var feature = new Feature(line, attributes);
    features.Add(feature);
}

features.SaveToShapefile(shpPath);

Reading features from a shapefile

foreach (var feature in ShapefileReader.ReadAll(shpPath))
{
    Console.WriteLine("Record ID: " + feature.Attributes["Id"]);
    foreach (var attrName in feature.Attributes.GetNames())
    {
        Console.WriteLine($"  {attrName}: {feature.Attributes[attrName]}");
    }
    Console.WriteLine($"  SHAPE: {feature.Geometry}");
}

Reading a SHP file geometries

foreach (var geom in ShapefileReader.ReadAllGeometries(shpPath))
{
    Console.WriteLine(geom);
}

Performance The core part of the library was designed with performance in mind. There is a lot of other optimizations, to name a few of them:

Encoding

The .NET Framework supports a large number of character encodings and code pages. On the other hand, .NET Core only supports limited list of encodings. To retrieve an encoding that is present in the .NET Framework on the Windows desktop but not in .NET Core, you need to do the following:

  1. Add to your project reference to to the System.Text.Encoding.CodePages.dll.
  2. Put the following line somewhere in your code:
    Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
CLAassistant commented 3 years ago

CLA assistant check
All committers have signed the CLA.

FObermaier commented 3 years ago

@kubaszostak , thanks for your valueable input, I assume your PR is ready for review?

KubaSzostak commented 3 years ago

Yes. It's ready for review.

kdethlefs commented 3 years ago

Any update on this? It's been since Feb 2021.

kdethlefs commented 3 years ago

Still curious if we have any update on this? @FObermaier what the next step to get this merged in?

DGuidi commented 2 years ago

not a big deal, but maybe we cah restore the original solution name NetTopologySuite.IO.Shapefile.sln instead of NetTopologySuite.IO.Esri.sln?

DGuidi commented 2 years ago

Thanks for the contribution. A totally minor issue: I see a lot of warnings and messages due to empty newline, whitespaces and unnecessary usings. some of then can be simply fixed using this default (I think) tool image

DGuidi commented 2 years ago

@kubaszostak Just to let you know that this test (from #80) fails also with "ESRI" lib

        /// <summary>
        /// <see href="https://github.com/NetTopologySuite/NetTopologySuite.IO.ShapeFile/issues/70"/>
        /// </summary>
        [Test]
        public void TestReadPolygonWithWrongShellOrientation()
        {
            /*
             * The shell_bad_ccw.shp contains a single polygon, with:
             *  - a shell CCW-oriented (like a hole from ESRI specs
             *  - a hole CW-oriented (like a shell from ESRI specs)
             */
            string filePath = Path.Combine(
                CommonHelpers.TestShapefilesDirectory,
                "shell_bad_ccw.shp");
            Assert.That(File.Exists(filePath), Is.True);
            var geoms = ShapefileReader.ReadAllGeometries(filePath);
            Assert.That(geoms, Is.Not.Null);
            Assert.That(geoms.Length, Is.EqualTo(1));
            var geom = geoms[0];
            Assert.That(geom, Is.Not.Null);
            Assert.That(geom.IsValid, Is.True);
            Assert.That(geom.NumGeometries, Is.EqualTo(1));
            Assert.That(geom, Is.InstanceOf<Polygon>());
            var poly = (Polygon)geom.GetGeometryN(0);
            Assert.That(poly.Shell, Is.Not.Null);
            Assert.That(poly.Holes, Is.Not.Null);
            Assert.That(poly.Holes.Length, Is.EqualTo(1));
        }

see also attached data shell_bad_ccw.zip.