using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using Deltares.Geographic;
using Deltares.Geometry;
using Deltares.Geotechnics;
using Deltares.Geotechnics.ConePenetrationTest;
using Deltares.Geotechnics.IO;
using Deltares.Geotechnics.IO.Importers;
using Deltares.Geotechnics.Mechanisms;
using Deltares.Geotechnics.Xsd;
using Deltares.MStab.IO.Classic;
using Deltares.Soilbase;
using Deltares.Stability;
using Deltares.Standard;
using Deltares.Standard.EventPublisher;
using Deltares.Standard.Forms;
using Deltares.Standard.Language;
using Deltares.Standard.Logging;
using Deltares.Standard.Maps;
using Deltares.Standard.Project;
using Deltares.Standard.Validation;
namespace Deltares.DSoilModel.Data
{
///
/// Exception type for DSoilModelProject
///
///
public class DSoilModelProjectException : Exception
{
public DSoilModelProjectException(string message): base(message)
{
}
}
///
/// D-Soil Model Project
///
public class DSoilModelProject : Project, IDisposable, IDomain
{
private readonly List bondStressCurves = new List();
private readonly List boringLookup1Ds = new List();
private readonly List boringLookup2Ds = new List();
private readonly List borings = new List();
private readonly List cptLookup1Ds = new List();
private readonly List cptLookup2Ds = new List();
private readonly List cpts = new List();
private readonly List currentSoilSegments = new List();
private readonly List soilProfiles1D = new List();
private readonly List soilProfiles2D = new List();
private readonly List soilSegments = new List();
private readonly List soilprofile1DLookup2Ds = new List();
private readonly List specificMechanismPointLocations = new List();
private readonly List stressCurves = new List();
private readonly List surfaceLines = new List();
private List dataSources = new List();
private SoilbaseDB soilbaseDB = new SoilbaseDB();
private SoilList soils = new SoilList();
private ParameterViewSettings parameterView = ParameterViewSettings.AllParameters;
private Mechanism currentFailureMechanism;
private const double noPoint = -9999123456789.0;
private const double geoTolerance = 0.001;
public const bool IsAutoValidationEnabled = true;
public DSoilModelProject()
{
// allow the project to provide lists of soils, stresscurves
Soil.DomainProvider = this;
SoilLayer.DomainProvider = this;
SoilSegment.DomainProvider = this;
TransformerManager.Transformer = new DSoilModelTransformer();
DataEventPublisher.OnAfterChange += DataEventPublisher_OnAfterChange;
DataEventPublisher.OnDataListModified += DataEventPublisher_OnDataListModified;
}
///
/// Currently selected (in the UI) parameter filter
///
public ParameterViewSettings ParameterView
{
get
{
return parameterView;
}
set
{
DataEventPublisher.BeforeChange(this, x => x.ParameterView);
parameterView = value;
DataEventPublisher.AfterChange(this, x => x.ParameterView);
}
}
///
/// Currently selected (in the UI) failure mechanism
///
public Mechanism CurrentFailureMechanism
{
get
{
return currentFailureMechanism;
}
set
{
DataEventPublisher.BeforeChange(this, "CurrentFailureMechanism");
currentFailureMechanism = value;
// Also set proper mechanism(s) for soil to get the proper filtering based on mechanism.
// Note: do NOT alter the MechanismeSupport.Mechanisms list, that may only be done in the plugin
// The MechanismeSupport.Mechanisms list controls the content of all available mechanisms for the product.
if (value != Mechanism.None)
{
Soil.Mechanisms = new[]
{
value
};
}
else
{
Soil.Mechanisms = MechanismSupport.Mechanisms;
}
FilterSegments();
DataEventPublisher.AfterChange(this, "CurrentFailureMechanism");
DataEventPublisher.DataListModified(Soils.Soils);
DataEventPublisher.DataListModified(CurrentSoilSegments);
DataEventPublisher.DoRefreshView(null, null);
}
}
///
/// SoilSegments for the currently selected Failure mechanism
///
public List CurrentSoilSegments
{
get
{
return currentSoilSegments;
}
}
///
/// Gets the CPTs (Cone Penetration Tests).
///
///
/// The CPTs.
///
[Validate]
public List CPTs
{
get
{
return cpts;
}
}
///
/// Gets the borings.
///
///
/// The borings.
///
[Validate]
public List Borings
{
get
{
return borings;
}
}
///
/// Gets or sets the soilbase database.
///
///
/// The soilbase database.
///
public SoilbaseDB SoilbaseDb
{
get
{
return soilbaseDB;
}
set
{
soilbaseDB = value;
}
}
///
/// Gets or sets the soils.
///
///
/// The soils.
///
[Validate]
public SoilList Soils
{
get
{
return soils;
}
set
{
soils = value;
}
}
///
/// Gets the 1D soil profiles.
///
///
/// The 1D soil profiles.
///
[Validate]
public List SoilProfiles1D
{
get
{
return soilProfiles1D;
}
}
///
/// Gets the 2D soil profiles.
///
///
/// The 2D soil profiles.
///
[Validate]
public List SoilProfiles2D
{
get
{
return soilProfiles2D;
}
}
///
/// Gets the 1D CPT lookups.
///
///
/// The 1D CPT lookups.
///
[Validate]
public List CptLookup1Ds
{
get
{
return cptLookup1Ds;
}
}
///
/// Gets the 2D CPT lookups.
///
///
/// The 2D CPT lookups.
///
[Validate]
public List CptLookup2Ds
{
get
{
return cptLookup2Ds;
}
}
///
/// Gets the 1D boring lookups.
///
///
/// The 1D boring lookups.
///
[Validate]
public List BoringLookup1Ds
{
get
{
return boringLookup1Ds;
}
}
///
/// Gets the 2D boring lookups.
///
///
/// The 2D boring lookups.
///
[Validate]
public List BoringLookup2Ds
{
get
{
return boringLookup2Ds;
}
}
///
/// Gets the specific mechanism point locations.
/// These locations define a local position where a 1D soilprofile is to be extracted from a 2D profile for calculations related to a specific failure mechanism.
///
[Validate]
public List SpecificMechanismPointLocations
{
get
{
return specificMechanismPointLocations;
}
}
///
/// Gets the 1D to 2D lookup list.
/// These loookups define a relative position for a 1D soil profile in a 2D soil profile,
///
[Validate]
public List Soilprofile1DLookup2Ds
{
get
{
return soilprofile1DLookup2Ds;
}
}
///
/// Gets the soil segments.
///
///
/// The soil segments.
///
[Validate]
public List SoilSegments
{
get
{
return soilSegments;
}
}
///
/// Gets the surface lines.
///
///
/// The surface lines.
///
[Validate]
public List SurfaceLines
{
get
{
return surfaceLines;
}
}
///
/// Gets the stress curves.
///
///
/// The stress curves.
///
[Validate]
public List StressCurves
{
get
{
return stressCurves;
}
}
///
/// Gets the bond stress curves.
///
///
/// The bond stress curves.
///
[Validate]
public List BondStressCurves
{
get
{
return bondStressCurves;
}
}
///
/// Gets the list of data sources
///
[Browsable(false)]
public List DataSources
{
get
{
return dataSources;
}
set
{
dataSources = value;
}
}
///
/// Reads a collection of SoilProfile1D from the given file (csv) and adds it to the project ensuring a unique name
///
///
public void ReadSoilProfiles1DFromFile(string fileName)
{
var soilsCount = Soils.Soils.Count;
var importer = new SosSoilProfilesImporter();
List profiles = importer.ReadSoilProfiles(fileName, Soils);
foreach (var profile in profiles)
{
AddSoilProfile1DToProject(profile);
}
if (importer.ErrorMessages.Count > 0)
{
// log the messages
DataEventPublisher.InvokeAndPublish(() =>
{
foreach (var msg in importer.ErrorMessages)
{
LogManager.Add(new LogMessage(LogMessageType.Warning, this, fileName + " : " + msg));
}
});
}
}
///
/// Reads a SoilProfile2d (geometry) from the given file (sti or geo) and adds it to the project ensuring a unique name
///
/// file name (*.sti, *.geo)
/// Option to ignore soils with duplicate names, drequired for DAM defx import
public SoilProfile2D ReadGeometryFromFile(string fileName, bool skipSoilsWithSameName = false)
{
CheckVersionInfo(fileName);
if (fileName.ToLower().EndsWith(".sti"))
{
SoilProfile2D sp2 = null;
StabilityModel stabilityModel = null;
try
{
var oldTransformer = TransformerManager.Transformer;
try
{
TransformerManager.Transformer = new DSoilModelStiFileTransformer();
var converter = new Converter();
stabilityModel = converter.ConvertClassicMStab(fileName);
}
finally
{
TransformerManager.Transformer = oldTransformer;
}
}
catch (Exception ex)
{
LogManager.Add(new LogMessage(LogMessageType.Error, typeof(Converter), ex.Message));
}
if (stabilityModel != null)
{
foreach (var soil in stabilityModel.SoilModel.Soils)
{
soil.UseDefaultShearStrengthModel = false;
}
AddSoilDataToProject(new SoilList
{
Soils = stabilityModel.SoilModel.Soils.ToList()
}, skipSoilsWithSameName);
sp2 = AddSoilProfile2DToProject(fileName, stabilityModel);
}
return sp2;
}
if (fileName.ToLower().EndsWith(".geo"))
{
var oldGeoImporter = new SoilProfile2DFromDSerieGeoFileImporter
{
Soils = soils.Soils
};
oldGeoImporter.ConvertToSoilProfile2D(fileName);
var sp2 = oldGeoImporter.SoilProfile2D;
if (sp2 != null)
{
// AddSoilDataToProject(oldGeoImporter.Soils); soils are handled in importer itself!
AddSoilProfile2DToProject(fileName, sp2);
}
return sp2;
}
Soil.DomainProvider = this;
SoilLayer.DomainProvider = this;
SoilSegment.DomainProvider = this;
TransformerManager.Transformer = new DSoilModelTransformer();
return null;
}
///
/// Checks the version information in the file.
///
/// The filename.
///
///
private void CheckVersionInfo(string filename)
{
const int highestSupportedSoilVersion = 1000;
const int highestSupportedGeometryVersion = 1001;
string[] fileLines = File.ReadAllLines(filename);
List fileContent = fileLines.ToList();
var dSerieImporterHelper = new DSerieImporterHelper();
DSerieFileInfo dSerieFileInfo = dSerieImporterHelper.ReadVersionInfo(filename, fileContent);
if ((dSerieFileInfo.DSerieFileType != DSerieFileType.DGeoStability) && (dSerieFileInfo.DSerieFileType != DSerieFileType.GeoFile))
{
throw new DSoilModelProjectException(String.Format(LocalizationManager.GetTranslatedText(this, "ErrorNoValidGeometryFile"), filename));
}
if (dSerieFileInfo.HasGeometryData)
{
if (dSerieFileInfo.GeometryVersionNumber > highestSupportedSoilVersion)
{
throw new DSoilModelProjectException(String.Format(LocalizationManager.GetTranslatedText(this, "ErrorNoValidGeometryData"), filename));
}
}
if (dSerieFileInfo.HasSoilData)
{
if (dSerieFileInfo.SoilVersionNumber > highestSupportedGeometryVersion)
{
throw new DSoilModelProjectException(String.Format(LocalizationManager.GetTranslatedText(this, "ErrorNoValidSoilData"), filename));
}
}
}
///
/// Reads a cpt from the given GEF file and adds it to the project ensuring a unique name
///
///
public bool ReadGefCptFromFile(string fileName)
{
ConePenetrationTestData conePenetrationTestData = null;
string lcFileName = fileName.ToLower();
if (lcFileName.EndsWith(".gef"))
{
var gefCptImporter = new GefCptFileImporter();
gefCptImporter.FillFromGefFile(fileName);
var messages = gefCptImporter.ErrorMessages;
if (messages.Count == 0)
{
conePenetrationTestData = gefCptImporter.ConePenetrationTestData;
}
}
if (conePenetrationTestData != null)
{
if (conePenetrationTestData.LevelType != CPTLevelType.NAP || conePenetrationTestData.XYCoordinateSystem != CPTXYCoordinateSystem.RD)
{
var msg = String.Format(LocalizationManager.GetTranslatedText(this, "gefCoordinateSystemError"), fileName);
LogManager.Add(new LogMessage(LogMessageType.Error, null, msg));
return false;
}
if (!IsValidRdCoordinate(conePenetrationTestData.X, conePenetrationTestData.Y))
{
var msg = String.Format(LocalizationManager.GetTranslatedText(this, "gefInvalidRdCoordinates"), fileName, conePenetrationTestData.X, conePenetrationTestData.Y);
LogManager.Add(new LogMessage(LogMessageType.Warning, null, msg));
conePenetrationTestData.X = 0;
conePenetrationTestData.Y = 0;
}
UniqueNameProvider.ProvideUniqueName(cpts, conePenetrationTestData);
cpts.Add(conePenetrationTestData);
return true;
}
return false;
}
///
/// Reads a boring from the given GEF file and adds it to the project ensuring a unique name
///
///
public bool ReadGefBoringFromFile(string fileName)
{
Boring boring = null;
if (fileName.ToLower().EndsWith(".gef"))
{
var gefBoringImporter = new GefBoringFileImporter();
gefBoringImporter.FillFromGefFile(fileName, soils);
boring = gefBoringImporter.Boring;
}
if (boring != null)
{
if (boring.ZcoordinateSystem != "NAP" || boring.XyCoordinateSystem != "RD")
{
var msg = String.Format(LocalizationManager.GetTranslatedText(this, "gefCoordinateSystemError"), fileName);
LogManager.Add(new LogMessage(LogMessageType.Error, null, msg));
return false;
}
if (!IsValidRdCoordinate(boring.X, boring.Y))
{
var msg = String.Format(LocalizationManager.GetTranslatedText(this, "gefInvalidRdCoordinates"), fileName, boring.X, boring.Y);
LogManager.Add(new LogMessage(LogMessageType.Warning, null, msg));
boring.X = 0;
boring.Y = 0;
}
// Ensure unique name
UniqueNameProvider.ProvideUniqueName(borings, boring);
borings.Add(boring);
return true;
}
return false;
}
///
/// Reads soils from the given old style database and adds them to the project ensuring unique names
///
///
public void ReadSoilsFromDatabase(string fileName)
{
DSoilModelIO.AddOldSoilDBToProject(fileName, this);
DataEventPublisher.DataListModified(soils.Soils);
}
///
/// Reads data from the given old style database (*.MDB, *.GDB) and adds it to the project ensuring unique names
///
///
public void ReadOldProjectFromDatabase(string fileName)
{
DSoilModelIO.AddOldProjectDataBaseToProject(fileName, this);
}
///
/// Gets the profiles.
///
/// The profile.
/// List of Soil Profiles
public IEnumerable GetProfiles(StochasticSoilProfile profile)
{
var list = new List();
list.AddRange(soilProfiles1D);
list.AddRange(soilProfiles2D);
return list;
}
///
/// Gets the CPTS.
///
/// The profile.
///
public IEnumerable GetCpts(ConePenetrationTestPerSegment conePenetrationTest)
{
var list = new List();
list.AddRange(cpts);
return list;
}
///
/// Gets the CPTS.
///
/// The cpt.
///
public IEnumerable GetCpts(SoilSegment cpt)
{
var list = new List();
list.AddRange(cpts);
return list;
}
///
/// Gets the borings.
///
/// The profile.
///
public IEnumerable GetBorings(SoilSegment boring)
{
var list = new List();
list.AddRange(borings);
return list;
}
///
/// Gets the borings.
///
/// The profile.
///
public IEnumerable GetBorings(BoringPerSegment boring)
{
var list = new List();
list.AddRange(borings);
return list;
}
///
/// Gets the surfaceLines.
///
/// The surfaceLine.
///
public IEnumerable GetSurfaceLines(SoilSegment surfaceLine)
{
var list = new List();
list.AddRange(surfaceLines);
return list;
}
///
/// Validation for the specific mechanism point locations on soil profile 2D.
///
[Validate]
public ValidationResult[] ValidateSpecificMechanismPointLocations()
{
var results = new List();
foreach (var soilProfile2D in soilProfiles2D)
{
SoilProfile2D thisSoilProfile2D = soilProfile2D;
List specificMechanismPointLocationsForThisSoilProfile =
specificMechanismPointLocations.Where(l => l.SoilProfile2D == thisSoilProfile2D).ToList();
foreach (var mechanism in Enum.GetValues(typeof(Mechanism)).Cast())
{
Mechanism thisMechanism = mechanism;
List locations =
specificMechanismPointLocationsForThisSoilProfile.Where(l => l.Mechanism == thisMechanism).ToList();
if (thisMechanism != Mechanism.None)
{
if (locations.Count > 1)
{
string messageForProfile = String.Format(this.Translate("MultipleSpecificMechanismPointLocationsOnProfile"),
locations.First().ToString().ToLower(), locations.Count);
results.Add(new ValidationResult(ValidationResultType.Error, messageForProfile, thisSoilProfile2D));
foreach (var location in locations)
{
string messageforLocation = String.Format(this.Translate("MultipleSpecificMechanismPointLocations"),
locations.First().ToString().ToLower(), thisSoilProfile2D.Name);
results.Add(new ValidationResult(ValidationResultType.Error, messageforLocation, location));
}
}
}
}
}
return results.ToArray();
}
///
/// Add soil data to the project, resolving duplicate names
///
/// soil data to add
/// determines how to handle duplicate names
public void AddSoilDataToProject(SoilList newSoilData, bool skipSoilsWithSameName = false)
{
if (newSoilData != null)
{
foreach (var newSoil in newSoilData.Soils)
{
var isNewSoil = true;
CheckStrengthModelSoil(newSoil);
foreach (var soilAlreadyKnown in soils.Soils)
{
if (soilAlreadyKnown.Name.Equals(newSoil.Name, StringComparison.InvariantCultureIgnoreCase))
{
if (skipSoilsWithSameName) // required for DAM defx import where soil properties from MDB files are leading
{
isNewSoil = false;
}
else
{
// Make sure the names are equal! Otherwise the comparison of the properties may fail
newSoil.Name = soilAlreadyKnown.Name;
if (soilAlreadyKnown.HasTheSameDeterministicValues(newSoil))
{
isNewSoil = false;
// check isAquifer dictionary ?
if (newSoilData.AquiferDictionary != null && newSoilData.AquiferDictionary.ContainsKey(newSoil))
{
if (Soils.AquiferDictionary != null && Soils.AquiferDictionary.ContainsKey(soilAlreadyKnown))
{
isNewSoil = (Soils.AquiferDictionary[soilAlreadyKnown] != newSoilData.AquiferDictionary[newSoil]);
}
}
}
}
break;
}
}
if (isNewSoil)
{
// Is a different soil with different properties that should be added under a new name
UniqueNameProvider.ProvideUniqueName(soils.Soils, newSoil);
soils.Add(newSoil);
if (newSoilData.AquiferDictionary != null && newSoilData.AquiferDictionary.ContainsKey(newSoil))
{
soils.AquiferDictionary.Add(newSoil, newSoilData.AquiferDictionary[newSoil]);
}
}
}
}
}
///
/// Repair all validation results for which a repair option is available
///
public void RepairAllValidationResults()
{
RealTimeBackgroundValidator.Instance.Stop();
foreach (var result in RealTimeBackgroundValidator.ValidationResults)
{
if (result.Repairer != null)
{
result.Repair();
}
}
if (IsAutoValidationEnabled)
{
RealTimeBackgroundValidator.Instance.Start();
}
}
///
/// Make sure that the separate lists of Soils, SoilProfiles etc. do represent all referenced objects in the datamodel.
///
public void UpdateLists()
{
foreach (var segment in soilSegments)
{
if (segment.StochasticSoilModel != null)
{
foreach (var profile in segment.StochasticSoilModel.StochasticSoilProfiles)
{
if (profile.Profile is SoilProfile1D)
{
if (!soilProfiles1D.Contains(profile.Profile))
{
soilProfiles1D.Add((SoilProfile1D) profile.Profile);
}
}
else if (profile.Profile is SoilProfile2D)
{
if (!soilProfiles2D.Contains(profile.Profile))
{
soilProfiles2D.Add((SoilProfile2D) profile.Profile);
}
}
}
}
if (segment.Cpts != null)
{
foreach (var cpt in segment.Cpts)
{
if (!cpts.Contains(cpt.ConePenetrationTestData))
{
cpts.Add(cpt.ConePenetrationTestData);
}
}
}
if (segment.Borings != null)
{
foreach (var boring in segment.Borings)
{
if (!borings.Contains(boring.Boring))
{
borings.Add(boring.Boring);
}
}
}
}
foreach (var profile in soilProfiles1D)
{
foreach (var layer in profile.Layers)
{
if (layer.Soil != null && !soils.Soils.Contains(layer.Soil))
{
soils.Add(layer.Soil);
}
}
}
foreach (var profile in soilProfiles2D)
{
foreach (var surface in profile.Surfaces)
{
if (surface.Soil != null && !soils.Soils.Contains(surface.Soil))
{
soils.Add(surface.Soil);
}
}
}
foreach (var soil in soils.Soils)
{
if (soil != null)
{
if (soil.StressTable != null && soil.StressTable.SigmaTaus.Count > 0)
{
if (!stressCurves.Contains(soil.StressTable))
{
stressCurves.Add(soil.StressTable);
}
}
if (soil.BondStressTable != null && soil.BondStressTable.BondStresses.Count > 0)
{
if (!bondStressCurves.Contains(soil.BondStressTable))
{
bondStressCurves.Add(soil.BondStressTable);
}
}
}
}
}
///
/// Dispose of unmanaged resources and delegates
///
public void Dispose()
{
foreach (var surfaceLine in SurfaceLines)
{
surfaceLine.Dispose();
}
surfaceLines.Clear();
DataEventPublisher.OnDataListModified -= DataEventPublisher_OnDataListModified;
DataEventPublisher.OnAfterChange -= DataEventPublisher_OnAfterChange;
}
///
/// Activates the first data. I.e. it provides a selectionchanged for the first soil or if no soil available, the first CPT.
/// This ensures the proper selection of the data line in the table and the belonging property window.
/// Trying to find other data than soil or CPT is useless as all other data objects should have soils.
/// Note: it does not set the proper table! That is handled in the plugin.
///
public void ActivateFirstData()
{
// Find a data field for which a selectionchanged can be send.
var firstSoil = soils.Soils.FirstOrDefault();
if (firstSoil != null)
{
DataEventPublisher.SelectionChanged(firstSoil);
}
else
{
var firstCPT = cpts.FirstOrDefault();
if (firstCPT != null)
{
DataEventPublisher.SelectionChanged(firstCPT);
}
}
}
///
/// Gets the domain.
///
/// The property.
/// the domain
public ICollection GetDomain(string property)
{
switch (property)
{
case "Soil":
return Soils.Soils;
case "CPT":
return CPTs;
case "Boring":
return Borings;
case "SurfaceLine":
return SurfaceLines;
case "SoilSegment":
return SoilSegments;
case "SoilProfile":
return SoilProfiles1D;
case "SoilProfile2D":
return SoilProfiles2D;
case "StressTable":
return StressCurves;
case "BondStressTable":
return BondStressCurves;
case "CurrentFailureMechanism":
return MechanismSupport.Mechanisms;
default:
return null;
}
}
private void DataEventPublisher_OnAfterChange(object sender, PublishEventArgs e)
{
// update CurrentSoilSegments subset on user edit (mechanism change)
if (sender is SoilSegment && e.Property == "Mechanism")
{
if (CurrentFailureMechanism != Mechanism.None)
{
FilterSegments();
}
}
}
private void DataEventPublisher_OnDataListModified(object sender, PublishEventArgs e)
{
if (sender == SoilSegments)
{
FilterSegments();
}
else if (sender == CurrentSoilSegments)
{
var args = e as DataListModifiedArgs;
if (args == null)
{
return;
}
switch (args.Action)
{
case ListModifyAction.Delete:
foreach (var segment in e.Objects.Cast().ToList())
{
soilSegments.Remove(segment);
}
break;
case ListModifyAction.Add:
case ListModifyAction.Insert:
foreach (var segment in e.Objects.Cast().ToList())
{
soilSegments.Add(segment);
}
break;
}
}
}
private void FilterSegments()
{
if (CurrentFailureMechanism != Mechanism.None)
{
currentSoilSegments.Clear();
currentSoilSegments.AddRange(soilSegments.Where(s => s.Mechanism == CurrentFailureMechanism));
}
else
{
currentSoilSegments.Clear();
currentSoilSegments.AddRange(soilSegments);
}
DataEventPublisher.DataListModified(CurrentSoilSegments);
}
// update current segments after adding/deleting a segment in the table
private void UpdateSegments() {}
private void AddSoilProfile1DToProject(SoilProfile1D profile)
{
UniqueNameProvider.ProvideUniqueName(soilProfiles1D, profile);
soilProfiles1D.Add(profile);
}
private SoilProfile2D AddSoilProfile2DToProject(string fileName, SoilProfile2D soilProfile2D)
{
soilProfile2D.Name = Path.GetFileName(fileName);
// Ensure unique name
UniqueNameProvider.ProvideUniqueName(soilProfiles2D, soilProfile2D);
soilProfile2D.XBegin = 0;
soilProfile2D.XEnd = soilProfile2D.Geometry.Right;
soilProfile2D.YBegin = 0;
soilProfile2D.YEnd = 0;
var loc = new GeographicPoint
{
X = soilProfile2D.Geometry.Right*0.5, Y = 0
};
soilProfile2D.Location = loc;
soilProfiles2D.Add(soilProfile2D);
return soilProfile2D;
}
private SoilProfile2D AddSoilProfile2DToProject(string fileName, StabilityModel stabilityModel)
{
if (stabilityModel.Geometry != null)
{
SoilProfile2D sp2D = stabilityModel.SoilProfile;
sp2D.Geometry.Rebox();
sp2D.Length = stabilityModel.Geometry.Right;
sp2D.Name = Path.GetFileName(fileName);
// Ensure unique name
UniqueNameProvider.ProvideUniqueName(soilProfiles2D, sp2D);
soilProfiles2D.Add(sp2D);
return sp2D;
}
return null;
}
///
/// Split a soil segment at given relative X coordinate
///
/// The segment to split
/// Local X coordinate
public void SplitSoilSegment(SoilSegment selectedSegment, double xSplit)
{
// Split the current selected segment into two "halves" as defined by the split location
if (selectedSegment != null)
{
var newSegment = new SoilSegment();
DataEventPublisher.BeforeChange(SoilSegments);
DataEventPublisher.BeforeChange(selectedSegment);
DataEventPublisher.BeforeChange(selectedSegment.Cpts);
DataEventPublisher.BeforeChange(selectedSegment.Points);
DataEventPublisher.InvokeWithoutPublishingEvents(() =>
{
newSegment.Assign(selectedSegment);
var oldName = selectedSegment.Name;
newSegment.Name = UniqueNameProvider.ProvideNewUniqueName(SoilSegments, oldName);
RearrangeSegmentCpts(selectedSegment, newSegment, xSplit);
RearrangeSegmentBorings(selectedSegment, newSegment, xSplit);
RearrangeSegmentPoints(selectedSegment, newSegment, xSplit);
var index = SoilSegments.IndexOf(selectedSegment);
if (index < SoilSegments.Count - 1)
{
SoilSegments.Insert(index + 1, newSegment);
}
else
{
SoilSegments.Add(newSegment);
}
var newName = UniqueNameProvider.ProvideNewUniqueName(SoilSegments, oldName);
selectedSegment.Name = newSegment.Name;
newSegment.Name = newName;
});
DataEventPublisher.AfterChange(selectedSegment.Points);
DataEventPublisher.DataListModified(SoilSegments);
DataEventPublisher.DataListModified(selectedSegment.Cpts);
DataEventPublisher.DataListModified(selectedSegment.Borings);
DataEventPublisher.DataListModified(selectedSegment.Points);
DataEventPublisher.SelectionChanged(selectedSegment, new SelectionEventArgs { Objects = new object[] { selectedSegment, newSegment }});
}
}
///
/// Link all selected CPT's and or Borings to the nearest (selected) segment(s)
///
public void LinkCptsAndBoringsToNearestSegment(object[] selectedObjects)
{
// objects to link
var cpts = selectedObjects.Where(o => o is ConePenetrationTestData).Cast().ToList();
var borings = selectedObjects.Where(o => o is Boring).Cast().ToList();
var segments = selectedObjects.Where(o => o is SoilSegment).Cast().ToList();
if (segments.Count == 0)
{
segments = SoilSegments;
}
foreach (var cpt in cpts)
{
LinkItemToSegments(cpt, segments);
}
foreach (var boring in borings)
{
LinkItemToSegments(boring, segments);
}
}
private void LinkItemToSegments(IGeographic item, List segments)
{
double nearestDistance = double.MaxValue;
IGeographic nearestItem = null;
SoilSegment nearestSegment = null;
foreach (var segment in segments)
{
double distance = DotSpatialGeographicAlgorithms.Distance(item, segment);
if (distance < nearestDistance)
{
nearestDistance = distance;
nearestItem = item;
nearestSegment = segment;
}
}
if (nearestItem != null)
{
// link segment to item
SetSegmentLinkAndLocalCoordinate(nearestSegment, nearestItem);
// check for other mechanism segment(s) with the same geographic definition and link to these as well
foreach (var segment in segments)
{
double distance = DotSpatialGeographicAlgorithms.Distance(item, segment);
if (Math.Abs(distance - nearestDistance) < GeometryConstants.Accuracy)
{
if (segment.Mechanism != nearestSegment.Mechanism && segment.Points.Count == nearestSegment.Points.Count)
{
if (CompareGeographicStrings(segment, nearestSegment))
{
SetSegmentLinkAndLocalCoordinate(segment, nearestItem);
}
}
}
}
}
}
private void SetSegmentLinkAndLocalCoordinate(SoilSegment segment, object item)
{
var itemPoint = item as IGeographicPoint;
if (itemPoint != null)
{
var segmentPoint = DotSpatialGeographicAlgorithms.NearestPointOnGeographicString(segment, itemPoint);
var xSegment = GeographicHelper.Instance.GetOffsetOnGeographicLineString(segmentPoint, segment);
// link to cpt ?
var cpt = item as ConePenetrationTestData;
if (cpt != null)
{
if (segment.Cpts.All(x => x.ConePenetrationTestData != cpt))
{
segment.Cpts.Add(new ConePenetrationTestPerSegment
{
ConePenetrationTestData = cpt,
Xlocal = xSegment
});
}
}
// link to boring ?
var boring = item as Boring;
if (boring != null)
{
if (segment.Borings.All(x => x.Boring != boring))
{
segment.Borings.Add(new BoringPerSegment
{
Boring = boring,
Xlocal = xSegment
});
}
}
}
}
private bool CompareGeographicStrings(IGeographicString geographicString1, IGeographicString geographicString2)
{
if (geographicString1.Points.Count != geographicString2.Points.Count)
{
return false;
}
for (int i = 0; i < geographicString1.Points.Count; i++)
{
if (Math.Abs(geographicString1.Points[i].X - geographicString2.Points[i].X) > GeometryConstants.Accuracy)
{
return false;
}
if (Math.Abs(geographicString1.Points[i].Y - geographicString2.Points[i].Y) > GeometryConstants.Accuracy)
{
return false;
}
}
return true;
}
private void RearrangeSegmentCpts(SoilSegment selectedSegment, SoilSegment newSegment, double xSplit)
{
foreach (var cptPerSegment in selectedSegment.Cpts)
{
if (cptPerSegment.Xlocal > xSplit)
{
var newCptPerSegment = new ConePenetrationTestPerSegment
{
Xlocal = cptPerSegment.Xlocal - xSplit,
ConePenetrationTestData = cptPerSegment.ConePenetrationTestData
};
newSegment.Cpts.Add(newCptPerSegment);
cptPerSegment.Xlocal = noPoint;
}
}
for (int i = selectedSegment.Cpts.Count - 1; i >= 0; i--)
{
if (Math.Abs(selectedSegment.Cpts[i].Xlocal - (noPoint)) < double.Epsilon)
{
selectedSegment.Cpts.Remove(selectedSegment.Cpts[i]);
}
}
}
private void RearrangeSegmentBorings(SoilSegment selectedSegment, SoilSegment newSegment, double xSplit)
{
foreach (var boringPerSegment in selectedSegment.Borings)
{
if (boringPerSegment.Xlocal > xSplit)
{
var newCptPerSegment = new BoringPerSegment
{
Xlocal = boringPerSegment.Xlocal,
Boring = boringPerSegment.Boring
};
newSegment.Borings.Add(newCptPerSegment);
boringPerSegment.Xlocal = noPoint;
}
}
for (int i = selectedSegment.Borings.Count - 1; i >= 0; i--)
{
if (Math.Abs(selectedSegment.Borings[i].Xlocal - (noPoint)) < double.Epsilon)
{
selectedSegment.Borings.Remove(selectedSegment.Borings[i]);
}
}
}
private void RearrangeSegmentPoints(SoilSegment selectedSegment, SoilSegment newSegment, double xSplit)
{
var addPoint = GeographicHelper.Instance.FindGeographicPointByOffsetOnLine(xSplit, selectedSegment);
var points = selectedSegment.Points.ToArray();
// find the index for split
double distance = 0;
int index = 0;
while (distance < xSplit)
{
index++;
distance += Distance(points[index], points[index - 1]);
}
// copy points per segment
selectedSegment.Points.Clear();
newSegment.Points.Clear();
newSegment.Points.Add(addPoint);
for (var i = 0; i < points.Length; i++)
{
if (i < index)
{
selectedSegment.Points.Add(points[i]);
}
else
{
newSegment.Points.Add(points[i]);
}
}
selectedSegment.Points.Add(addPoint);
// check for (almost) duplicate points
var n = selectedSegment.Points.Count - 1;
if (Distance(selectedSegment.Points[n], selectedSegment.Points[n-1]) < geoTolerance) selectedSegment.Points.RemoveAt(n-1);
if (Distance(newSegment.Points[0], newSegment.Points[1]) < geoTolerance) newSegment.Points.RemoveAt(1);
}
private double Distance(IGeographicPoint point1, IGeographicPoint point2)
{
var dx = point2.X - point1.X;
var dy = point2.Y - point1.Y;
return Math.Sqrt(dx * dx + dy * dy);
}
// Check the stress model for the given - set to None if not C-Phi or Su berekend
private void CheckStrengthModelSoil(Soil soil)
{
if (soil.ShearStrengthModel != ShearStrengthModel.CPhi && soil.ShearStrengthModel != ShearStrengthModel.CuCalculated && soil.ShearStrengthModel != ShearStrengthModel.CuCalculatedYield)
{
soil.ShearStrengthModel = ShearStrengthModel.None;
LogManager.Add(new LogMessage(LogMessageType.Warning, this, string.Format(LocalizationManager.GetTranslatedText(this, "UnknownStrengthModel"), soil.Name)));
}
if (soil.ShearStrengthModel == ShearStrengthModel.CuCalculatedYield)
{
soil.ShearStrengthModel = ShearStrengthModel.CuCalculated;
soil.UsePop = false;
}
}
///
/// Determines whether provided x,y coordinates are valid RD coordinates (Rijks Driehoekstelsel).
///
/// The x coordinate.
/// The y coordinate.
///
/// true if [is valid rd coordinate] [the specified x]; otherwise, false.
///
private bool IsValidRdCoordinate(double x, double y)
{
// valid coordinate range taken from wikipedia: https://nl.wikipedia.org/wiki/Rijksdriehoeksco%C3%B6rdinaten#Geldigheidsgebied
const double xRdMin = -7000;
const double xRdMax = 300000;
const double yRdMin = 289000;
const double yRdMax = 629000;
return (x >= xRdMin && x <= xRdMax && y >= yRdMin && y <= yRdMax);
}
}
}