using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using System.Xml;
using Deltares.DeltaModel;
using Deltares.Geotechnics;
using Deltares.Geotechnics.IO;
using Deltares.Geotechnics.IO.Importers;
using Deltares.Soilbase;
using Deltares.Standard;
using Deltares.Standard.Maps;
using Deltares.Standard.EventPublisher;
using Deltares.Standard.Extensions;
using Deltares.Standard.IO;
using Deltares.Standard.Language;
using Deltares.Standard.Logging;
namespace Deltares.DSoilModel.Data
{
public class DSoilModelIO
{
///
/// Adds data from an old database (gdb or access) to the given project. All name clashes are resolved by renaming (uniquely) the
/// here imported items.
///
/// Name of the file.
/// The project.
public static void AddOldProjectDataBaseToProject(string fileName, DSoilModelProject project)
{
DataEventPublisher.InvokeWithoutPublishingEvents(() =>
{
using (var geoDatabase = new GeoDatabase(fileName))
{
try
{
ReadSoilsFromOldDataBaseAndAddToProject(ref project, geoDatabase);
ReadSoilProfilesFromOldDatabaseAndAddToProject(ref project, geoDatabase);
ReadSoilProfiles2DFromOldDatabaseAndAddToProject(ref project, geoDatabase);
ReadCptsFromOldDatabaseAndAddToProject(ref project, geoDatabase);
ReadBoringsFromOldDatabaseAndAddToProject(ref project, geoDatabase);
ReadSegmentsFromOldDatabaseAndAddToProject(ref project, geoDatabase);
}
catch (Exception e)
{
var message = LocalizationManager.GetTranslatedText(typeof(DSoilModelIO), "OldProjectImportError");
var logmessage = new LogMessage(LogMessageType.Error, typeof(DSoilModelIO), message + e.Message);
LogManager.Messages.Add(logmessage);
}
}
});
}
///
/// Adds the soil data from an old database (gdb or access) to the given project. All name clashes are resolved by renaming
/// (uniquely) the here imported items.
///
/// Name of the file.
/// The project.
public static void AddOldSoilDBToProject(string fileName, DSoilModelProject project)
{
DataEventPublisher.IsDataEventPublishStopped = true;
using (var geoDatabase = new GeoDatabase(fileName))
{
ReadSoilsFromOldDataBaseAndAddToProject(ref project, geoDatabase);
}
DataEventPublisher.IsDataEventPublishStopped = false;
}
///
/// Reads all data from the current database and add that to the newly created current project.
///
/// Name of the file.
/// the created project
public static object OpenSoilDatabase(string fileName)
{
LogManager.Clear();
DataEventPublisher.DataListModified(LogManager.Messages);
var oldStopped = DataEventPublisher.IsDataEventPublishStopped;
DataEventPublisher.IsDataEventPublishStopped = true;
// READ PROJECT FILE FROM NEW DATABASE FORMAT
var project = new DSoilModelProject();
using (var db = new SoilModelDatabase())
{
db.HandleExceptions = true;
db.Open(fileName);
project.StressCurves.AddRange(db.ReadStressCurves());
project.BondStressCurves.AddRange(db.ReadBondStressCurves());
project.Soils = db.ReadSoils();
project.CPTs.AddRange(db.ReadCPTs());
project.Borings.AddRange(db.ReadBorings(project.Soils));
project.SoilProfiles1D.AddRange(db.ReadSoilProfiles1D());
project.SoilProfiles2D.AddRange(db.ReadSoilProfiles2D());
project.CptLookup1Ds.AddRange(db.ReadCPTLookup1Ds());
project.CptLookup2Ds.AddRange(db.ReadCPTLookup2Ds());
project.BoringLookup1Ds.AddRange(db.ReadBoringLookup1Ds(project.Soils));
project.BoringLookup2Ds.AddRange(db.ReadBoringLookup2Ds(project.Soils));
project.Soilprofile1DLookup2Ds.AddRange(db.ReadSoilProfile1DLookup2Ds());
project.SpecificMechanismPointLocations.AddRange(db.ReadMechanismPointLocations());
project.SoilSegments.AddRange(db.ReadSoilSegments());
db.ReadSoilSegmentCPTs();
db.ReadSoilSegmentBorings(project.Soils);
project.SurfaceLines.AddRange(db.ReadSurfaceLines());
db.Close();
// report errors
if (db.ErrorMessages.Count > 0)
{
LogManager.Add(new LogMessage(LogMessageType.Error, project, LocalizationManager.GetTranslatedText(project, "ErrorOpeningProject")));
foreach (var msg in db.ErrorMessages)
{
LogManager.Add(msg);
}
DataEventPublisher.DataListModified(LogManager.Messages);
MessageBox.Show(LocalizationManager.GetTranslatedText(project, "OpenDataBaseErrors"));
}
}
DataEventPublisher.IsDataEventPublishStopped = oldStopped;
return project;
}
///
/// Saves all data from the given project to the current database
///
/// Name of the file.
/// The project.
public static void SaveSoilDatabase(string fileName, object project)
{
try
{
fileName = Path.ChangeExtension(fileName, "soil");
var dsProject = project as DSoilModelProject;
if (dsProject == null)
{
return;
}
DataEventPublisher.IsDataEventPublishStopped = true;
// SAVE PROJECT TO NEW DATABASE FORMAT
using (var db = new SoilModelDatabase())
{
db.New(fileName);
db.WriteStressCurves(dsProject.StressCurves);
db.WriteBondStressCurves(dsProject.BondStressCurves);
db.WriteSoils(dsProject.Soils.Soils);
db.WriteCPTs(dsProject.CPTs);
db.WriteBorings(dsProject.Borings);
db.WriteSoilProfile1Ds(dsProject.SoilProfiles1D);
db.WriteSoilProfile2Ds(dsProject.SoilProfiles2D);
db.WriteCPTLookup1Ds(dsProject.CptLookup1Ds);
db.WriteCPTLookup2Ds(dsProject.CptLookup2Ds);
db.WriteBoringLookup1Ds(dsProject.BoringLookup1Ds);
db.WriteBoringLookup2Ds(dsProject.BoringLookup2Ds);
db.WriteSoilProfile1DLookup2Ds(dsProject.Soilprofile1DLookup2Ds);
db.WriteMechanismPointLocations(dsProject.SpecificMechanismPointLocations);
db.WriteSurfaceLines(dsProject.SurfaceLines);
db.WriteSoilSegments(dsProject.SoilSegments);
db.WriteSoilSegmentCPTs(dsProject.SoilSegments);
db.WriteSoilSegmentBorings(dsProject.SoilSegments);
db.Close();
}
}
catch (Exception ex)
{
string msg = String.Format(LocalizationManager.GetTranslatedText(typeof(DSoilModelIO), "ErrorSavingProject"), ex.Message);
MessageBox.Show(msg, "", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);
}
finally
{
DataEventPublisher.IsDataEventPublishStopped = false;
}
}
///
/// Reads surface line definition from CSV format (DAM Style)
///
///
public static void ReadCsvSurfaceLineFromFileAndAddToProject(string fileName, DSoilModelProject project)
{
var importer = new SurfaceLinesImporter();
var surfaceLine2List = importer.ReadSurfacesLines(fileName);
foreach (var surfaceLine2 in surfaceLine2List)
{
UniqueNameProvider.ProvideUniqueName(project.SurfaceLines, surfaceLine2);
project.SurfaceLines.Add(surfaceLine2);
}
foreach (var msg in importer.ErrorMessages)
{
LogMessage(fileName + " : " + msg, project);
}
}
///
/// Reads surface line characteristic points definition from CSV format (DAM Style)
///
///
public static void ReadCsvCharacteristicPointsFromFileAndAddToProject(string fileName, DSoilModelProject project)
{
var importer = new CharacteristicPointsImporter();
importer.Read(fileName, project.SurfaceLines);
foreach (var msg in importer.ErrorMessages)
{
LogMessage(fileName + " : " + msg, project);
}
}
///
/// Reads soil segment definition from CSV format (DAM Style)
///
/// file name of the CSV file to import
/// the D-SoilModel project
/// controls rejection of soil segments with incomplete soil profile data (default == true)
public static void ReadCsvSegmentsFromFileAndAddToProject(string fileName, DSoilModelProject project, bool rejectIncompleteSegments = true)
{
var importer = new SoilSegmentsImporter();
var soilProfiles = new List();
soilProfiles.AddRange(project.SoilProfiles1D);
soilProfiles.AddRange(project.SoilProfiles2D);
var segments = importer.ReadSoilSegments(fileName, soilProfiles);
foreach (var segment in segments.ToArray())
{
// refuse segments with missing SoilProfile
if (rejectIncompleteSegments && segment.StochasticSoilModel.StochasticSoilProfiles.Any(p => p.Profile == null || p.Profile.GetType() == typeof(SoilProfile)))
{
string msg = String.Format(LocalizationManager.GetTranslatedText(typeof(DSoilModelIO), "SoilSegmentRefused"), segment.Name);
LogManager.Add(new LogMessage(LogMessageType.Warning, project, msg));
}
else
{
UniqueNameProvider.ProvideUniqueName(project.SoilSegments, segment);
project.SoilSegments.Add(segment);
}
}
foreach (var msg in importer.ErrorMessages)
{
LogMessage(fileName + " : " + msg, project);
}
}
///
/// Reads Dam soil segment & surfaceline data from the given file (defx or damx) and adds it to the project ensuring unique names for the imported items
///
/// name of the file to import (*.defx; *.damx)
/// project to add the imported data to
public static void ReadDamDefinitionsFromFileAndAddToProject(string fileName, DSoilModelProject project)
{
string dummy = "";
ReadDamDefinitionsFromFileAndAddToProject(fileName, project, ref dummy);
}
///
/// Reads Dam soil segment & surfaceline data from the given file (defx or damx) and adds it to the project ensuring unique names for the imported items
///
/// name of the file to import (*.defx; *.damx)
/// project to add the imported data to
/// returns the path of the locations shapefile, if defined
public static void ReadDamDefinitionsFromFileAndAddToProject(string fileName, DSoilModelProject project, ref string locationsShpFile)
{
var stopped = DataEventPublisher.IsDataEventPublishStopped;
DataEventPublisher.IsDataEventPublishStopped = true;
try
{
// convert file to lower case before parsing it using xpath
string xml;
using (StreamReader sr = new StreamReader(fileName))
{
xml = sr.ReadToEnd();
}
var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml.ToLower());
var root = "//" + xmlDoc.DocumentElement.Name;
var xmlNode = xmlDoc.SelectSingleNode(root);
string geometryDir = GetNodeAttribute(xmlNode, "mapsoilprofile2d");
xmlNode = xmlDoc.SelectSingleNode(root + "/datasourcelist/datasource[@datasourcetype='csvfiles']");
string csvDir = GetNodeAttribute(xmlNode, "datalocation");
xmlNode = xmlDoc.SelectSingleNode(root + "/datasourcelist/datasource[@datasourcetype='datashapefiles']");
string shapeDir = (xmlNode != null) ? GetNodeAttribute(xmlNode, "datalocation") : "";
xmlNode = xmlDoc.SelectSingleNode(root + "/datasourcelist/datasource[@datasourcetype='msoilbase']");
string soilMdb = (xmlNode != null) ? GetNodeAttribute(xmlNode, "datalocation") : "";
xmlNode = xmlDoc.SelectSingleNode(root + "/dataattributes/attribute[@id='segment_id']");
string segmentShp = (xmlNode != null) ? GetNodeAttribute(xmlNode, "datasource") : "";
string segmentField = (xmlNode != null) ? GetNodeAttribute(xmlNode, "name") : "";
xmlNode = xmlDoc.SelectSingleNode(root + "/dataattributes/attribute[@id='location_id']");
locationsShpFile = (xmlNode != null) ? Path.Combine(shapeDir, GetNodeAttribute(xmlNode, "datasource")) : "";
string basePath = Path.GetDirectoryName(fileName) + Path.DirectorySeparatorChar;
// soils
if (soilMdb != null)
{
LogManager.Add(new LogMessage(LogMessageType.Info, typeof(DSoilModelProject), "..." + basePath + soilMdb));
using (var soilBase = new GeoDatabase(basePath + soilMdb))
{
ReadSoilsFromOldDataBaseAndAddToProject(ref project, soilBase);
soilBase.Close();
}
}
// soilprofiles (1D only)
string csvFile = Path.Combine(basePath, csvDir, "soilprofiles.csv");
if (File.Exists(csvFile))
{
LogManager.Add(new LogMessage(LogMessageType.Info, typeof(DSoilModelProject), "..." + csvFile));
project.ReadSoilProfiles1DFromFile(csvFile);
}
// segments
csvFile = Path.Combine(basePath, csvDir, "segments.csv");
if (File.Exists(csvFile))
{
LogManager.Add(new LogMessage(LogMessageType.Info, typeof(DSoilModelProject), "..." + csvFile));
ReadCsvSegmentsFromFileAndAddToProject(csvFile, project, false);
// read 2D profiles referenced by these segments ?
if (geometryDir != null)
{
foreach (var segment in project.SoilSegments)
{
foreach (var profile in segment.StochasticSoilModel.StochasticSoilProfiles)
{
if (profile.Profile.GetType() == typeof(SoilProfile))
{
var name = profile.Profile.Name;
if (name.ToLower().EndsWith(".sti"))
{
var stiFile = Path.Combine(basePath, geometryDir, name);
var existing = project.SoilProfiles2D.FirstOrDefault(p => p.Name == name);
if (existing != null)
{
profile.Profile = existing;
}
else if (File.Exists(stiFile))
{
try
{
// de-serialize
LogManager.Add(new LogMessage(LogMessageType.Info, typeof(DSoilModelProject), "..." + stiFile));
var sp2D = project.ReadGeometryFromFile(stiFile, true);
if (sp2D != null)
{
// assign to stochastic profile
profile.Profile = sp2D;
// clear log message(s) now that the geometry is loaded
foreach (var msg in LogManager.Messages.Where(m => m.Message.EndsWith(sp2D.Name)).ToArray())
{
LogManager.Messages.Remove(msg);
}
}
}
catch (Exception ex)
{
LogMessage(String.Format("Error reading Geometry from file: {0} ({1})", stiFile, ex.Message), project);
}
}
else
{
LogMessage("file not found :" + stiFile, project);
}
}
}
}
}
}
// reject incomplete segments (profiles not imported as SoilProfile1D or SoilProfile2D)
foreach (var segment in project.SoilSegments.ToArray())
{
if (segment.StochasticSoilModel.StochasticSoilProfiles.Any( p => p.Profile.GetType() == typeof(SoilProfile)))
{
project.SoilSegments.Remove(segment);
string msg = String.Format(LocalizationManager.GetTranslatedText(typeof(DSoilModelIO), "SoilSegmentRefused"), segment.Name);
LogMessage(msg, project);
}
}
}
// segments shape file ?
var shpFile = Path.Combine(basePath, shapeDir, segmentShp);
if (!string.IsNullOrEmpty(segmentShp))
{
if (File.Exists(shpFile))
{
LogManager.Add(new LogMessage(LogMessageType.Info, typeof(DSoilModelProject), "..." + segmentShp));
ReadSegmentShapefileAndAddToProject(shpFile, project, segmentField);
}
else
{
string msg = String.Format(LocalizationManager.GetTranslatedText(typeof(DSoilModelIO), "FileNotFound"), segmentShp);
LogMessage(msg, project);
}
}
// surfacelines
csvFile = Path.Combine(basePath, csvDir, "surfacelines.csv");
if (File.Exists(csvFile))
{
LogManager.Add(new LogMessage(LogMessageType.Info, typeof(DSoilModelProject), "..." + csvFile));
ReadCsvSurfaceLineFromFileAndAddToProject(csvFile, project);
}
csvFile = Path.Combine(basePath, csvDir, "characteristicpoints.csv");
if (File.Exists(csvFile))
{
LogManager.Add(new LogMessage(LogMessageType.Info, typeof(DSoilModelProject), "..." + csvFile));
ReadCsvCharacteristicPointsFromFileAndAddToProject(csvFile, project);
}
}
catch (Exception ex)
{
string msg = String.Format(LocalizationManager.GetTranslatedText(typeof(DSoilModelIO), "DamimportError"), ex.Message);
LogMessage(msg, project);
}
finally
{
DataEventPublisher.IsDataEventPublishStopped = stopped;
DataEventPublisher.DataListModified(project.Soils.Soils);
DataEventPublisher.DataListModified(project.SoilProfiles1D);
DataEventPublisher.DataListModified(project.SoilProfiles2D);
DataEventPublisher.DataListModified(project.SoilSegments);
DataEventPublisher.DataListModified(project.SurfaceLines);
}
}
public static void ReadSegmentShapefileAndAddToProject(string fileName, DSoilModelProject project, string fieldName = "SegmentId")
{
// import segments shapefile to empty deltamodel
var importer = new ShapeFileImporter();
var deltaModel = new DeltaModel.DeltaModel();
var fieldMap = new FieldPropertyMap();
fieldMap.Definitions.Add(new FieldDefinition(fieldName, "SegmentId", true));
importer.FieldDefinition = fieldMap;
importer.Type = typeof(SoilSegment);
importer.FileName = fileName;
importer.Factory = new DeltaModelFactory(deltaModel);
importer.Import();
// link geography to existing segments (imported from CSV)
foreach (var shapeSegment in deltaModel.SoilSegments)
{
string name = shapeSegment.Name;
foreach (var segment in project.SoilSegments.Where(s => s.Name == name || s.Name.StartsWith(name + "_")))
{
segment.Points.Clear();
segment.Points.AddRange(shapeSegment.Points);
}
}
}
private static void ReadSoilsFromOldDataBaseAndAddToProject(ref DSoilModelProject project, GeoDatabase geoDatabase)
{
SoilList newSoils = geoDatabase.ReadSoils(new List());
project.AddSoilDataToProject(newSoils, false);
// backward compatibility, isAquifer dictionary
foreach (var newSoil in newSoils.Soils)
{
// Set Aquifer dictionary too
if (newSoils.AquiferDictionary.ContainsKey(newSoil))
{
if (project.Soils.AquiferDictionary.ContainsKey(newSoil))
{
project.Soils.AquiferDictionary[newSoil] = newSoils.AquiferDictionary[newSoil];
}
else
{
project.Soils.AquiferDictionary.Add(newSoil, newSoils.AquiferDictionary[newSoil]);
}
}
}
}
private static void ReadSoilProfilesFromOldDatabaseAndAddToProject(ref DSoilModelProject project, GeoDatabase geoDatabase)
{
var soilProfiles = geoDatabase.ReadSoilProfiles(project.Soils.Soils);
foreach (var soilProfile1D in soilProfiles)
{
// Make sure of unique name
UniqueNameProvider.ProvideUniqueName(project.SoilProfiles1D, soilProfile1D);
project.SoilProfiles1D.Add(soilProfile1D);
}
}
private static void ReadSoilProfiles2DFromOldDatabaseAndAddToProject(ref DSoilModelProject project, GeoDatabase geoDatabase)
{
var soilProfiles2D = geoDatabase.ReadSoilProfiles2D(project.Soils.Soils);
foreach (var soilProfile2D in soilProfiles2D)
{
// Make sure of unique name
UniqueNameProvider.ProvideUniqueName(project.SoilProfiles2D, soilProfile2D);
project.SoilProfiles2D.Add(soilProfile2D);
}
}
private static void ReadCptsFromOldDatabaseAndAddToProject(ref DSoilModelProject project, GeoDatabase geoDatabase)
{
var cpts = geoDatabase.ReadCPTs();
foreach (var cpt in cpts)
{
// Make sure of unique name
UniqueNameProvider.ProvideUniqueName(project.CPTs, cpt);
project.CPTs.Add(cpt);
}
}
private static void ReadBoringsFromOldDatabaseAndAddToProject(ref DSoilModelProject project, GeoDatabase geoDatabase)
{
var borings = geoDatabase.ReadBorings(project.Soils);
foreach (var boring in borings)
{
// Make sure of unique name
UniqueNameProvider.ProvideUniqueName(project.Borings, boring);
project.Borings.Add(boring);
}
}
private static void ReadSegmentsFromOldDatabaseAndAddToProject(ref DSoilModelProject project, GeoDatabase geoDatabase)
{
var segments = geoDatabase.ReadSegments();
foreach (var segment in segments)
{
// Make sure of unique name
UniqueNameProvider.ProvideUniqueName(project.SoilSegments, segment);
project.SoilSegments.Add(segment);
}
}
private static string GetNodeAttribute(XmlNode node, string attribute)
{
// reading xml attribute, null safe
if (node != null)
{
var att = node.Attributes[attribute];
return (att != null) ? att.Value : null;
}
return null;
}
private static void LogMessage(string message, object source)
{
var stopped = DataEventPublisher.IsDataEventPublishStopped;
DataEventPublisher.IsDataEventPublishStopped = false;
LogManager.Add(new LogMessage(LogMessageType.Warning, source, message));
DataEventPublisher.IsDataEventPublishStopped = stopped;
}
}
}