// Copyright (C) Stichting Deltares and State of the Netherlands 2025. All rights reserved.
//
// This file is part of Riskeer.
//
// Riskeer 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.Collections.Generic;
using System.IO;
using System.Linq;
using Core.Common.Base.Geometry;
using Core.Common.Base.IO;
using Core.Common.Util.Builders;
using Core.Components.Gis.Data;
using Core.Components.Gis.Features;
using Core.Components.Gis.Geometries;
using DotSpatial.Data;
using GeoAPI.Geometries;
using CoreCommonUtilResources = Core.Common.Util.Properties.Resources;
using GisIOResources = Core.Components.Gis.IO.Properties.Resources;
namespace Core.Components.Gis.IO.Readers
{
///
/// Class to be used to read polylines from a shapefile.
///
public class PolylineShapeFileReader : ShapeFileReaderBase
{
private int readIndex;
///
/// Initializes a new instance of the class.
///
/// The shapefile path.
/// Thrown when is invalid.
/// Thrown when either:
///
/// - points to a file that doesn't exist.
/// - The shapefile has non-line geometries in it.
/// - An unexpected error occurred when reading the shapefile.
///
///
public PolylineShapeFileReader(string shapeFilePath) : base(shapeFilePath)
{
try
{
ShapeFile = new LineShapefile(shapeFilePath);
}
catch (ArgumentException exception)
{
string message = new FileReaderErrorMessageBuilder(shapeFilePath)
.Build(GisIOResources.PolylineShapeFileReader_File_contains_geometries_not_line);
throw new CriticalFileReadException(message, exception);
}
catch (IOException exception)
{
string message = new FileReaderErrorMessageBuilder(shapeFilePath).Build(CoreCommonUtilResources.Error_General_IO_Import_ErrorMessage);
throw new CriticalFileReadException(message, exception);
}
}
///
/// Reads a line shape from the file.
///
/// The representing the read line shape, or
/// null when at the end of the shapefile.
public override FeatureBasedMapData ReadFeature(string name = null)
{
if (readIndex == GetNumberOfFeatures())
{
return null;
}
try
{
IFeature lineFeature = GetFeature(readIndex);
return ConvertSingleLineFeatureToMapLineData(lineFeature, !string.IsNullOrWhiteSpace(name)
? name
: GisIOResources.PolylineShapeFileReader_ReadLine_Line);
}
finally
{
readIndex++;
}
}
public override FeatureBasedMapData ReadShapeFile(string name = null)
{
var featureList = new List();
while (readIndex != GetNumberOfFeatures())
{
featureList.Add(ReadFeatureLine());
}
return ConvertMultiLineFeatureToMapLineData(featureList, !string.IsNullOrWhiteSpace(name) ? name : GisIOResources.PolylineShapeFileReader_ReadLine_Line);
}
///
/// 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.
public override IFeature GetFeature(int index)
{
return ShapeFile.Features[index];
}
private IFeature ReadFeatureLine()
{
try
{
return GetFeature(readIndex);
}
finally
{
readIndex++;
}
}
private MapLineData ConvertSingleLineFeatureToMapLineData(IFeature lineFeature, string name)
{
MapFeature feature = CreateMapFeatureForLineFeature(lineFeature);
CopyMetaDataIntoFeature(feature, readIndex);
return new MapLineData(name)
{
Features = new[]
{
feature
}
};
}
private MapLineData ConvertMultiLineFeatureToMapLineData(IEnumerable lineFeatures, string name)
{
int lineFeaturesCount = lineFeatures.Count();
var mapFeatures = new MapFeature[lineFeaturesCount];
for (var featureIndex = 0; featureIndex < lineFeaturesCount; featureIndex++)
{
IFeature lineFeature = lineFeatures.ElementAt(featureIndex);
MapFeature feature = CreateMapFeatureForLineFeature(lineFeature);
CopyMetaDataIntoFeature(feature, featureIndex);
mapFeatures[featureIndex] = feature;
}
var mapLineData = new MapLineData(name)
{
Features = mapFeatures
};
mapLineData.SelectedMetaDataAttribute = mapLineData.MetaData.FirstOrDefault();
return mapLineData;
}
private static MapFeature CreateMapFeatureForLineFeature(IFeature lineFeature)
{
var geometries = new List();
for (var i = 0; i < lineFeature.Geometry.NumGeometries; i++)
{
IGeometry polylineGeometry = lineFeature.Geometry.GetGeometryN(i);
var mapGeometry = new MapGeometry(GetMapGeometryPointCollections(polylineGeometry.Coordinates));
geometries.Add(mapGeometry);
}
return new MapFeature(geometries);
}
private static IEnumerable> GetMapGeometryPointCollections(IEnumerable lineCoordinates)
{
return new[]
{
lineCoordinates.Select(c => new Point2D(c.X, c.Y)).ToArray()
};
}
}
}