// 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 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 General Public License for more details.
//
// You should have received a copy of the GNU 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.Collections.ObjectModel;
using System.IO;
using System.Linq;
using Core.Common.Base.Data;
using Core.Common.Base.Geometry;
using Core.Common.Base.IO;
using Core.Common.IO.Exceptions;
using Core.Common.IO.Readers;
using log4net;
using Ringtoets.Common.Data.AssessmentSection;
using Ringtoets.Common.IO.Properties;
using Ringtoets.Common.IO.Structures;
namespace Ringtoets.Common.IO.FileImporters
{
///
/// Abstact class for structure importers, providing an implementation of importing point shapefiles
/// containing structure locations and csv files containing structure schematizations.
///
public abstract class StructuresImporter : FileImporterBase
{
protected readonly ILog log = LogManager.GetLogger(typeof(StructuresImporter));
private readonly ReferenceLine referenceLine;
///
/// Initializes a new instance of .
///
/// The import target.
/// The reference line used to check if the imported structures are intersecting it.
/// The path to the file to import from.
/// Thrown when ,
/// or is null.
protected StructuresImporter(T importTarget, ReferenceLine referenceLine, string filePath)
: base(filePath, importTarget)
{
if (referenceLine == null)
{
throw new ArgumentNullException("referenceLine");
}
this.referenceLine = referenceLine;
}
public override bool Import()
{
ReadResult importStructureLocationsResult = ReadStructureLocations();
if (importStructureLocationsResult.CriticalErrorOccurred)
{
return false;
}
if (Canceled)
{
HandleUserCancellingImport();
return false;
}
ReadResult importStructureParameterRowsDataResult = ReadStructureParameterRowsData();
if (importStructureParameterRowsDataResult.CriticalErrorOccurred)
{
return false;
}
if (Canceled)
{
HandleUserCancellingImport();
return false;
}
CreateStructures(importStructureLocationsResult, importStructureParameterRowsDataResult);
return true;
}
///
/// Act upon the user cancelling the import operation.
///
protected virtual void HandleUserCancellingImport()
{
Canceled = false;
}
///
/// Create structure objects from location and geometry data.
///
/// The read structure locations.
/// The read structure parameters, grouped by location identifier.
protected abstract void CreateSpecificStructures(ICollection structureLocations,
Dictionary> groupedStructureParameterRows);
protected void LogMessages(ValidationResult validationResult, int lineNumber)
{
foreach (string message in validationResult.ErrorMessages)
{
log.Error(message);
}
log.ErrorFormat(Resources.StructuresImporter_Structure_number_0_is_skipped, lineNumber);
}
protected RoundedDouble GetStandardDeviation(StructuresParameterRow structuresParameterRow)
{
if (structuresParameterRow.VarianceType == VarianceType.CoefficientOfVariation)
{
log.WarnFormat(Resources.StructuresImporter_StandardDeviation_Converting_variation_on_Line_0_,
structuresParameterRow.LineNumber);
return (RoundedDouble) structuresParameterRow.VarianceValue*Math.Abs(structuresParameterRow.NumericalValue);
}
return (RoundedDouble) structuresParameterRow.VarianceValue;
}
protected RoundedDouble GetCoefficientOfVariation(StructuresParameterRow structuresParameterRow)
{
if (structuresParameterRow.VarianceType == VarianceType.StandardDeviation)
{
log.WarnFormat(Resources.StructuresImporter_GetCoefficientOfVariation_Converting_variation_on_Line_0_,
structuresParameterRow.LineNumber);
return (RoundedDouble) (structuresParameterRow.VarianceValue/Math.Abs(structuresParameterRow.NumericalValue));
}
return (RoundedDouble) structuresParameterRow.VarianceValue;
}
private void CreateStructures(ReadResult importStructureLocationsResult,
ReadResult importStructureParameterRowsDataResult)
{
Dictionary> groupedRows =
importStructureParameterRowsDataResult.ImportedItems
.GroupBy(row => row.LocationId)
.ToDictionary(g => g.Key, g => g.ToList());
CreateSpecificStructures(importStructureLocationsResult.ImportedItems, groupedRows);
}
private ReadResult ReadStructureParameterRowsData()
{
NotifyProgress(Resources.StructuresImporter_ReadStructureParameterRowsData_reading_structure_data, 1, 1);
string csvFilePath = Path.ChangeExtension(FilePath, ".csv");
var rowsReader = new StructuresCharacteristicsCsvReader(csvFilePath);
int totalNumberOfRows;
try
{
totalNumberOfRows = rowsReader.GetLineCount();
}
catch (CriticalFileReadException exception)
{
log.Error(exception.Message);
return new ReadResult(true);
}
var rows = new List();
for (int i = 0; i < totalNumberOfRows; i++)
{
if (Canceled)
{
return new ReadResult(false);
}
NotifyProgress(Resources.StructuresImporter_ReadStructureParameterRowsData_reading_structuredata, i + 1, totalNumberOfRows);
try
{
StructuresParameterRow row = rowsReader.ReadLine();
rows.Add(row);
}
catch (CriticalFileReadException exception)
{
log.Error(exception.Message);
}
catch (LineParseException exception)
{
log.Error(exception.Message);
}
}
return new ReadResult(false)
{
ImportedItems = rows
};
}
private ReadResult ReadStructureLocations()
{
NotifyProgress(Resources.StructuresImporter_ReadStructureLocations_reading_structurelocations, 1, 1);
try
{
using (var structureLocationReader = new StructureLocationReader(FilePath))
{
return GetStructureLocationReadResult(structureLocationReader);
}
}
catch (CriticalFileReadException exception)
{
log.Error(exception.Message);
}
catch (ArgumentException exception)
{
log.Error(exception.Message);
}
return new ReadResult(true);
}
private ReadResult GetStructureLocationReadResult(StructureLocationReader structureLocationReader)
{
var structureLocations = new Collection();
int totalNumberOfSteps = structureLocationReader.GetStructureCount;
for (int i = 0; i < totalNumberOfSteps; i++)
{
if (Canceled)
{
return new ReadResult(false);
}
try
{
NotifyProgress(Resources.StructuresImporter_GetStructureLocationReadResult_reading_structurelocation, i + 1, totalNumberOfSteps);
AddNextStructureLocation(structureLocationReader, structureLocations);
}
catch (LineParseException exception)
{
var message = string.Format(
Resources.StructuresImporter_GetStructureLocationReadResult_Error_reading_Structure_LineNumber_0_Error_1_The_Structure_is_skipped,
i + 1,
exception.Message);
log.Warn(message);
}
}
return new ReadResult(false)
{
ImportedItems = structureLocations
};
}
///
/// Get the next from
/// and add to in case it is close enough to the .
///
/// Reader reading objects from a shapefile.
/// Collection of objects
/// to which the new is to be added.
///
/// - The shapefile misses a value for a required attribute.
/// - The shapefile has an attribute whose type is incorrect.
///
private void AddNextStructureLocation(StructureLocationReader structureLocationReader, ICollection structureLocations)
{
StructureLocation structureLocation = structureLocationReader.GetNextStructureLocation();
double distanceToReferenceLine = GetDistanceToReferenceLine(structureLocation.Point);
if (distanceToReferenceLine > 1.0)
{
log.ErrorFormat(Resources.StructuresImporter_AddNextStructureLocation_0_skipping_location_outside_referenceline, structureLocation.Id);
return;
}
if (structureLocations.Any(dpl => dpl.Id.Equals(structureLocation.Id)))
{
log.WarnFormat(Resources.StructuresImporter_AddNextStructureLocation_Location_with_kwkident_0_already_read, structureLocation.Id);
}
structureLocations.Add(structureLocation);
}
private double GetDistanceToReferenceLine(Point2D point)
{
return GetLineSegments(referenceLine.Points).Min(segment => segment.GetEuclideanDistanceToPoint(point));
}
private static IEnumerable GetLineSegments(IEnumerable linePoints)
{
return Math2D.ConvertLinePointsToLineSegments(linePoints);
}
}
}