NetTopologySuite / NetTopologySuite.IO.ShapeFile

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

DbaseFileHeader.Fields index off by one vs ShapeFileDataReader.GetValue #12

Closed FarbrorMartin closed 6 years ago

FarbrorMartin commented 6 years ago

I am upgrading from an older version of NTS and my code for reading the attribute tables does not work.

I use DbaseFileHeader.Fields to find the field indices and then use ShapeFileDataReader.GetValue(idx) to read the value from the attribute table. Using the new NTS I'm getting some strange behavior: Index 0 in DbaseFileHeader.Fields returns the first field in the attribute table (i.e. ObjectId) as expected. But ShapeFileDataReader.GetValue(0) returns the geometry object, and index 1 returns the ObjectId value. Is this by design?


GeometryFactory factory = new GeometryFactory(new PrecisionModel(PrecisionModels.Fixed),3006);

            var features = new List<Feature>();
            using ( ShapefileDataReader shapeFileDataReader = new ShapefileDataReader(shpFilename, factory))
            {

                ShapefileHeader shpHeader = shapeFileDataReader.ShapeHeader;

                DbaseFileHeader header = shapeFileDataReader.DbaseHeader;
                while (shapeFileDataReader.Read())
                {
                    Feature feature = new Feature();
                    AttributesTable attributesTable = new AttributesTable();
                    IGeometry geometry = (Geometry)shapeFileDataReader.Geometry;
                    for (int i = 0; i < header.NumFields; i++)
                    {
                        DbaseFieldDescriptor fldDescriptor = header.Fields[i];
                        attributesTable.Add(fldDescriptor.Name, shapeFileDataReader.GetValue(i)); 
                    }
                    feature.Geometry = geometry;
                    feature.Attributes = attributesTable;
                    features.Add(feature);
                }
                shapeFileDataReader.Close();
            }

Thanks

airbreather commented 6 years ago

Is this by design?

Yes, I believe so. Prior to NetTopologySuite/NetTopologySuite@b946c24, the IGeometry itself was not actually visible when just using the IDataReader / IDataRecord API, which is why I imagine we took that technically breaking change. Edit: I may be wrong about which commit the change was in, but I do remember noticing it at the time.

Here's my really quick attempt at tweaking this... I haven't tested it at all, YMMV:

GeometryFactory factory = new GeometryFactory(new PrecisionModel(PrecisionModels.Fixed),3006);

var features = new List<Feature>();
using ( ShapefileDataReader shapeFileDataReader = new ShapefileDataReader(shpFilename, factory))
{
    string[] fieldNames = new string[shapeFileDataReader.FieldCount];
    for (int i = 0; i < fieldNames.Length; i++)
    {
        fieldNames[i] = shapeFileDataReader.GetName(i);
    }

    while (shapeFileDataReader.Read())
    {
        AttributesTable attributesTable = new AttributesTable();

        // skip the geometry column at index 0.
        for (int i = 1; i < fieldNames.Length; i++)
        {
            attributesTable.Add(fieldNames[i], shapeFileDataReader.GetValue(i)); 
        }

        Feature feature = new Feature(shapeFileDataReader.Geometry, attributesTable);
        features.Add(feature);
    }
}
airbreather commented 6 years ago

@FarbrorMartin did my comment resolve your issue?

FarbrorMartin commented 6 years ago

Hi I solved it by offsetting the index. It’s not dufficult to work around, I was mostly wondering if it was a bug or by design. It’s an odd design choice I think. It’s no real problem for me since I know about it now, but for new users it’s probably confusing. So your answer solved my problem :)

tors 30 aug. 2018 kl. 14:25 skrev Joe Amenta notifications@github.com:

@FarbrorMartin https://github.com/FarbrorMartin did my comment resolve your issue?

— You are receiving this because you were mentioned.

Reply to this email directly, view it on GitHub https://github.com/NetTopologySuite/NetTopologySuite.IO.ShapeFile/issues/12#issuecomment-417300555, or mute the thread https://github.com/notifications/unsubscribe-auth/AjJ1-3O4tcAEuHIJn3ucgvk69B-IV8XQks5uV9mtgaJpZM4Vy034 .

airbreather commented 6 years ago

It’s an odd design choice I think.

It's to make sure that when this is used in places that accept arbitrary IDataReader, we still surface the most important part of the data 😅.

Closing it, thanks for replying.