// 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.Geometry; using Core.Common.Base.IO; using Core.Common.IO.Exceptions; using Core.Common.IO.Readers; using Ringtoets.Common.Data.AssessmentSection; using Ringtoets.Common.Data.DikeProfiles; using Ringtoets.Common.Data.Exceptions; using Ringtoets.Common.IO.DikeProfiles; using Ringtoets.Common.IO.Exceptions; using Ringtoets.Common.IO.FileImporters.MessageProviders; using Ringtoets.Common.IO.Properties; namespace Ringtoets.Common.IO.FileImporters { /// /// Abstract class for profile importers, providing an implementation of importing point shapefiles /// containing dike profile locations and text files containing dike schematizations. /// /// public abstract class ProfilesImporter : FileImporterBase { protected readonly IImporterMessageProvider MessageProvider; private readonly ReferenceLine referenceLine; private readonly string typeDescriptor; /// /// Initializes a new instance of . /// /// The reference line used to check if the imported profiles are intersecting it. /// The path to the file to import from. /// The import target. /// The message provider to provide messages during the import. /// The description of the profiles that are imported. /// Thrown when any input parameter is null. protected ProfilesImporter(ReferenceLine referenceLine, string filePath, T importTarget, IImporterMessageProvider messageProvider, string typeDescriptor) : base(filePath, importTarget) { if (referenceLine == null) { throw new ArgumentNullException(nameof(referenceLine)); } if (messageProvider == null) { throw new ArgumentNullException(nameof(messageProvider)); } if (typeDescriptor == null) { throw new ArgumentNullException(nameof(typeDescriptor)); } this.referenceLine = referenceLine; this.typeDescriptor = typeDescriptor; MessageProvider = messageProvider; } protected override bool OnImport() { ReadResult importDikeProfilesResult = ReadProfileLocations(); if (importDikeProfilesResult.CriticalErrorOccurred || Canceled) { return false; } string folderPath = Path.GetDirectoryName(FilePath); string[] acceptedIds = importDikeProfilesResult.Items.Select(dp => dp.Id).ToArray(); ReadResult importDikeProfileDataResult = ReadDikeProfileData(folderPath, acceptedIds); if (importDikeProfileDataResult.CriticalErrorOccurred || Canceled) { return false; } NotifyProgress(MessageProvider.GetAddDataToModelProgressText(), 1, 1); try { CreateProfiles(importDikeProfilesResult, importDikeProfileDataResult); } catch (UpdateDataException e) { string message = string.Format(MessageProvider.GetUpdateDataFailedLogMessageText( typeDescriptor), e.Message); Log.Error(message, e); return false; } catch (CriticalFileReadException e) { Log.Error(e.Message); return false; } return true; } /// /// Create profile objects from location and geometry data. /// /// The read profile locations. /// The read dike profile geometries. /// Thrown when /// does not contain data for a location in . /// Thrown when applying updates to the data model has failed. protected abstract void CreateProfiles(ReadResult importProfileLocationResult, ReadResult importDikeProfileDataResult); /// /// Construct a from a dike profile geometry. /// /// The dike profile geometry. /// A new . protected static BreakWater CreateBreakWater(DikeProfileData dikeProfileData) { switch (dikeProfileData.DamType) { case DamType.Caisson: return new BreakWater(BreakWaterType.Caisson, dikeProfileData.DamHeight); case DamType.HarborDam: return new BreakWater(BreakWaterType.Dam, dikeProfileData.DamHeight); case DamType.Vertical: return new BreakWater(BreakWaterType.Wall, dikeProfileData.DamHeight); } return null; } /// /// Obtain the dike profile geometry object matching a given . /// /// The available dike profile geometry objects. /// The id on which to match. /// The matching . protected static DikeProfileData GetMatchingDikeProfileData(IEnumerable dikeProfileDataCollection, string id) { return dikeProfileDataCollection.FirstOrDefault(d => d.Id.Equals(id)); } /// /// Validate the consistency of a object. /// /// The to validate. /// Filepath of the profile data file. /// Value indicating whether the is valid. protected abstract bool DikeProfileDataIsValid(DikeProfileData data, string prflFilePath); private ReadResult ReadProfileLocations() { NotifyProgress(Resources.ProfilesImporter_ReadProfileLocations_reading_profilelocations, 1, 1); try { using (var profileLocationReader = new ProfileLocationReader(FilePath)) { return GetProfileLocationReadResult(profileLocationReader); } } catch (CriticalFileReadException exception) { Log.Error(exception.Message); } catch (ArgumentException exception) { Log.Error(exception.Message); } return new ReadResult(true); } private ReadResult GetProfileLocationReadResult(ProfileLocationReader profileLocationReader) { var profileLocations = new Collection(); int totalNumberOfSteps = profileLocationReader.GetLocationCount; for (var i = 0; i < totalNumberOfSteps; i++) { if (Canceled) { return new ReadResult(false); } try { NotifyProgress(Resources.ProfilesImporter_GetProfileLocationReadResult_reading_profilelocation, i + 1, totalNumberOfSteps); AddNextProfileLocation(profileLocationReader, profileLocations); } catch (LineParseException exception) { string message = string.Format( Resources.ProfilesImporter_GetProfileLocationReadResult_Error_reading_Profile_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 = profileLocations }; } /// /// 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 locations for a profile. /// Thrown when either: /// /// The shapefile misses a value for a required attribute. /// The shapefile has an attribute whose type is incorrect. /// The read is outside the reference line. /// private void AddNextProfileLocation(ProfileLocationReader profileLocationReader, ICollection profileLocations) { ProfileLocation profileLocation = profileLocationReader.GetNextProfileLocation(); double distanceToReferenceLine = GetDistanceToReferenceLine(profileLocation.Point); if (distanceToReferenceLine > 1.0) { throw new LineParseException(string.Format(Resources.ProfilesImporter_AddNextProfileLocation_Location_with_id_0_outside_referenceline, profileLocation.Id)); } if (profileLocations.Any(dpl => dpl.Id.Equals(profileLocation.Id))) { string message = string.Format(Resources.ProfilesImporter_AddNextProfileLocation_Location_with_id_0_already_read, profileLocation.Id); throw new CriticalFileReadException(message); } profileLocations.Add(profileLocation); } private ReadResult ReadDikeProfileData(string folderPath, string[] acceptedIds) { NotifyProgress(Resources.ProfilesImporter_ReadDikeProfileData_reading_profile_data, 1, 1); // No exception handling for GetFiles, as folderPath is derived from an existing, read file. string[] prflFilePaths = Directory.GetFiles(folderPath, "*.prfl"); int totalNumberOfSteps = prflFilePaths.Length; var dikeProfileData = new Collection(); var dikeProfileDataReader = new DikeProfileDataReader(acceptedIds); for (var i = 0; i < totalNumberOfSteps; i++) { if (Canceled) { return new ReadResult(false); } string prflFilePath = prflFilePaths[i]; try { NotifyProgress(Resources.ProfilesImporter_ReadDikeProfileData_reading_profiledata, i + 1, totalNumberOfSteps); DikeProfileData data = dikeProfileDataReader.ReadDikeProfileData(prflFilePath); if (!DikeProfileDataIsValid(data, prflFilePath)) { continue; } if (data.SheetPileType != SheetPileType.Coordinates) { Log.Error(string.Format(Resources.ProfilesImporter_ReadDikeProfileData_sheet_piling_not_zero_skipping_0_, prflFilePath)); continue; } if (dikeProfileData.Any(d => d.Id.Equals(data.Id))) { string errorMessage = string.Format( Resources.ProfilesImporter_LogDuplicateDikeProfileData_Multiple_DikeProfileData_found_for_DikeProfile_0_File_1_skipped, data.Id, prflFilePath); throw new CriticalFileReadException(errorMessage); } dikeProfileData.Add(data); } catch (CriticalFileReadException exception) { Log.Error(exception.Message); return new ReadResult(true); } catch (CriticalFileValidationException) { // Ignore file } } return new ReadResult(false) { Items = dikeProfileData }; } private double GetDistanceToReferenceLine(Point2D point) { return GetLineSegments(referenceLine.Points).Min(segment => segment.GetEuclideanDistanceToPoint(point)); } private static IEnumerable GetLineSegments(IEnumerable linePoints) { return Math2D.ConvertPointsToPolygonSegments(linePoints); } } }