// Copyright (C) Stichting Deltares 2016. All rights reserved.
//
// This file is part of Ringtoets.
//
// Ringtoets is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see .
//
// All names, logos, and references to "Deltares" are registered trademarks of
// Stichting Deltares and remain full property of Stichting Deltares at all times.
// All rights reserved.
using System;
using System.Data;
using System.IO;
using System.Linq;
using Core.Common.Base.Geometry;
using Core.Common.IO.Exceptions;
using Core.Common.Utils;
using Core.Common.Utils.Builders;
using Core.Components.Gis.Data;
using DotSpatial.Data;
using CoreCommonUtilsResources = Core.Common.Utils.Properties.Resources;
using GisIOResources = Core.Components.Gis.IO.Properties.Resources;
namespace Core.Components.Gis.IO
{
///
/// Class to be used to read polylines from a shapefile.
///
public class PolylineShapeFileReader : IDisposable
{
private readonly string filePath;
private readonly LineShapefile lineShapeFile;
private int readIndex;
///
/// Initializes a new instance of the class.
///
/// The shapefile path.
/// When is invalid.
/// When either:
///
/// - points to a file that doesn't exist.
/// - The shapefile has non-line geometries in it.
///
public PolylineShapeFileReader(string shapeFilePath)
{
FileUtils.ValidateFilePath(shapeFilePath);
if (!File.Exists(shapeFilePath))
{
string message = new FileReaderErrorMessageBuilder(shapeFilePath)
.Build(CoreCommonUtilsResources.Error_File_does_not_exist);
throw new CriticalFileReadException(message);
}
filePath = shapeFilePath;
try
{
lineShapeFile = new LineShapefile(shapeFilePath);
}
catch (ArgumentException e)
{
string message = new FileReaderErrorMessageBuilder(shapeFilePath)
.Build(GisIOResources.LineShapeFileReader_File_contains_geometries_not_line);
throw new CriticalFileReadException(message, e);
}
}
///
/// Gets the number of lines in the shapefile.
///
public int GetNumberOfLines()
{
return lineShapeFile.Features.Count;
}
///
/// Reads a line shape from the file.
///
/// The representing the read line shape, or
/// null when at the end of the shapefile.
/// When reading a multi-line feature.
public MapLineData ReadLine(string name = null)
{
if (readIndex == lineShapeFile.Features.Count)
{
return null;
}
try
{
IFeature lineFeature = GetSingleLineFeature(readIndex);
return ConvertSingleLineFeatureToMapLineData(lineFeature, name ?? GisIOResources.PolylineShapeFileReader_ReadLine_Line);
}
finally
{
readIndex++;
}
}
///
/// Determines whether the specified attribute has been defined in the shapefile attributes.
///
/// Name of the attribute.
/// True is the attribute is defined, false otherwise.
/// This check is case-sensitive.
public bool HasAttribute(string attributeName)
{
return lineShapeFile.Attributes.Columns.Any(c => c.ColumnName == attributeName);
}
public void Dispose()
{
lineShapeFile.Close();
}
///
/// Gets the single line feature at the given index.
///
/// The index of which feature to retrieve.
/// The feature that consists out of 1 whole polyline.
/// When reading a multi-line feature.
private IFeature GetSingleLineFeature(int index)
{
IFeature lineFeature = lineShapeFile.Features[index];
if (lineFeature.NumGeometries > 1)
{
string message = new FileReaderErrorMessageBuilder(filePath)
.WithLocation(string.Format(GisIOResources.PolylineShapeFileReader_GetSingleLineFeature_At_shapefile_index_0_, index))
.Build(GisIOResources.PolylineShapeFileReader_ReadLine_Read_unsupported_multipolyline);
throw new ElementReadException(message);
}
return lineFeature;
}
private MapLineData ConvertSingleLineFeatureToMapLineData(IFeature lineFeature, string name)
{
var lineData = new MapLineData(lineFeature.Coordinates.Select(c => new Point2D(c.X, c.Y)), name);
DataTable table = lineShapeFile.GetAttributes(readIndex, 1);
DataRow dataRow = table.Rows[0];
for (int i = 0; i < table.Columns.Count; i++)
{
lineData.MetaData[table.Columns[i].ColumnName] = dataRow[i];
}
return lineData;
}
}
}