// Copyright (C) Stichting Deltares 2017. 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 Core.Common.Utils.Builders; using log4net; using Ringtoets.Common.Data.AssessmentSection; using Ringtoets.Common.IO.Properties; using Ringtoets.Common.IO.Structures; namespace Ringtoets.Common.IO.FileImporters { /// /// Abstract 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 { private 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(nameof(referenceLine)); } this.referenceLine = referenceLine; } protected override bool OnImport() { ReadResult importStructureLocationsResult = ReadStructureLocations(); if (importStructureLocationsResult.CriticalErrorOccurred || Canceled) { return false; } ReadResult importStructureParameterRowsDataResult = ReadStructureParameterRowsData(); if (importStructureParameterRowsDataResult.CriticalErrorOccurred || Canceled) { return false; } NotifyProgress(Resources.Importer_ProgressText_Adding_imported_data_to_data_model, 1, 1); CreateStructures(importStructureLocationsResult, importStructureParameterRowsDataResult); return true; } protected override void LogImportCanceledMessage() { log.Info(Resources.StructuresImporter_User_canceled); } /// /// 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 RoundedDouble GetStandardDeviation(StructuresParameterRow structuresParameterRow, string structureName) { if (structuresParameterRow.VarianceType == VarianceType.CoefficientOfVariation) { log.WarnFormat(Resources.StructuresImporter_GetStandardDeviation_Converting_variation_StructureName_0_StructureId_1_ParameterId_2_on_Line_3_, structureName, structuresParameterRow.LocationId, structuresParameterRow.ParameterId, structuresParameterRow.LineNumber); return (RoundedDouble) structuresParameterRow.VarianceValue * Math.Abs(structuresParameterRow.NumericalValue); } return (RoundedDouble) structuresParameterRow.VarianceValue; } protected RoundedDouble GetCoefficientOfVariation(StructuresParameterRow structuresParameterRow, string structureName) { if (structuresParameterRow.VarianceType == VarianceType.StandardDeviation) { log.WarnFormat(Resources.StructuresImporter_GetCoefficientOfVariation_Converting_variation_StructureName_0_StructureId_1_ParameterId_2_on_Line_3_, structureName, structuresParameterRow.LocationId, structuresParameterRow.ParameterId, structuresParameterRow.LineNumber); return (RoundedDouble) (structuresParameterRow.VarianceValue / Math.Abs(structuresParameterRow.NumericalValue)); } return (RoundedDouble) structuresParameterRow.VarianceValue; } protected void LogValidationErrorForStructure(string structureName, string structureId, IEnumerable validationErrors) { string shortMessage = new FileReaderErrorMessageBuilder(GetStructureDataCsvFilePath()) .WithSubject(string.Format(Resources.StructuresImporter_StructureName_0_StructureId_1_, structureName, structureId)) .Build(Resources.StructuresImporter_LogValidationErrorForStructure_Click_details_for_full_message_0_); string messageRemainder = string.Format(Resources.StructuresImporter_LogValidationErrorForStructure_One_or_more_erors_skip_structure_ErrorMessageList_0_, string.Join(Environment.NewLine, validationErrors.Select(msg => "* " + msg))); log.ErrorFormat(shortMessage, messageRemainder); } protected void TrySetConstructionProperty(Action, string> setPropertyAction, IDictionary rowData, string key, string structureName, string structureId) { if (rowData.ContainsKey(key)) { setPropertyAction(rowData, key); } else { log.Info(string.Format(Resources.StructuresImporter_TrySetConstructionProperty_Parameter_0_of_StructureName_1_StructureId_2_missing_or_invalid_default_values_used, key, structureName, structureId)); } } private string GetStructureDataCsvFilePath() { return Path.ChangeExtension(FilePath, ".csv"); } private void CreateStructures(ReadResult importStructureLocationsResult, ReadResult importStructureParameterRowsDataResult) { Dictionary> groupedRows = importStructureParameterRowsDataResult.Items .GroupBy(row => row.LocationId) .ToDictionary(g => g.Key, g => g.ToList()); CreateSpecificStructures(importStructureLocationsResult.Items, groupedRows); } private ReadResult ReadStructureParameterRowsData() { NotifyProgress(Resources.StructuresImporter_ReadStructureParameterRowsData_reading_structure_data, 1, 1); string csvFilePath = GetStructureDataCsvFilePath(); using (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 (var 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); return new ReadResult(true); } catch (LineParseException exception) { log.Error(exception.Message); } } return new ReadResult(false) { Items = 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 (var 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) { string message = string.Format( Resources.StructuresImporter_GetStructureLocationReadResult_Error_reading_Structure_LineNumber_0_Error_1_, i + 1, exception.Message); log.Error(message, exception); return new ReadResult(true); } catch (CriticalFileReadException exception) { log.Error(exception.Message); return new ReadResult(true); } } return new ReadResult(false) { Items = 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. /// Thrown when the /// reads multiple structures for a structure. /// Thrown when either: /// /// 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))) { string message = string.Format(Resources.StructuresImporter_AddNextStructureLocation_Location_with_kwkident_0_already_read, structureLocation.Id); throw new CriticalFileReadException(message); } 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); } } }