// 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); } } }