// Copyright (C) Stichting Deltares 2017. All rights reserved. // // This file is part of the Dam Engine. // // The Dam Engine is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero 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 Affero General Public License for more details. // // You should have received a copy of the GNU Affero 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.Linq; using Deltares.DamEngine.Data.Geometry; using Deltares.DamEngine.Data.Standard; using Deltares.DamEngine.Data.Standard.Validation; namespace Deltares.DamEngine.Data.Geotechnics { /// /// /// A SoilSurfaceProfile constructs a SoilProfile2D object by merging an existing SoilProfile1D with a SurfaceLine /// /// Note that actual contruction of 2D based on surface line and 1D happens on setting the properties using dirty flags. /// public class SoilSurfaceProfile : SoilProfile2D { private Soil dikeEmbankmentMaterial; private bool dirty; private bool initial = true; private SoilProfile1D soilProfile; private SoilProfile1D orgSoilProfile; private GeometryPointString surfaceLine; private SurfaceLine2 surfaceLine2; private bool createSettlementZones; /// /// Initializes a new instance of the class. /// public SoilSurfaceProfile() { Name = "Soil Surface Profile"; } /// /// Gets or sets the surface line. /// /// /// The surface line. /// [Validate] public GeometryPointString SurfaceLine { get { return surfaceLine; } set { surfaceLine = value; dirty = true; } } /// /// Gets or sets the surface line2. /// [Validate] public SurfaceLine2 SurfaceLine2 { get { return surfaceLine2; } set { surfaceLine2 = value; if (surfaceLine2 != null) { SurfaceLine = surfaceLine2.Geometry; } else { SurfaceLine = null; } dirty = true; } } /// /// Gets or sets the soil profile. /// /// /// The soil profile. /// [Validate] public SoilProfile1D SoilProfile { get { return orgSoilProfile; } set { orgSoilProfile = value; dirty = true; } } /// /// Gets or sets the dike material. /// /// /// The dike material. /// public Soil DikeEmbankmentMaterial { get { return dikeEmbankmentMaterial; } set { dikeEmbankmentMaterial = value; dirty = true; } } /// /// List of preconsolidation stresses /// public override List PreconsolidationStresses { get { if (orgSoilProfile != null) { return orgSoilProfile.PreconsolidationStresses; } return null; } } /// /// Gets the surfaces. /// /// /// The surfaces. /// [Validate] public override IList Surfaces { get { if (initial || dirty) { UpdateLayers(); } return base.Surfaces; } } /// /// Gets or sets a value indicating whether to [create settlement zones]. /// /// /// true if [create settlement zones]; otherwise, false. /// public bool CreateSettlementZones { get { return createSettlementZones; } set { createSettlementZones = value; } } /// /// Generates a 1D profile at a given x /// /// /// Generated 1D soil profile public override SoilProfile1D GetSoilProfile1D(double x) { if (initial || dirty) { initial = false; UpdateLayers(); } // Try to obtain a cached soil profile (performance optimization) var soilProfile1D = GetCachedSoilProfile1D(x); if (soilProfile1D != null) { return soilProfile1D; } // Otherwise, create and configure a new soil profile soilProfile1D = new SoilProfile1D(); double top = SurfaceLine.GetZatX(x); soilProfile1D.BottomLevel = soilProfile.BottomLevel; if (top > soilProfile.TopLevel) { var emptyTopLayer = new SoilLayer1D(null, top) { SoilProfile = soilProfile1D }; soilProfile1D.Layers.Add(emptyTopLayer); } for (int i = 0; i < soilProfile.Layers.Count; i++) { SoilLayer1D layer = soilProfile.Layers[i]; if (layer.BottomLevel < top) { // Perform without publishing events because otherwise the soil profile cache would get lost var newLayer = new SoilLayer1D(layer.Soil, Math.Min(layer.TopLevel, top)) { IsAquifer = layer.IsAquifer, WaterpressureInterpolationModel = layer.WaterpressureInterpolationModel, SoilProfile = soilProfile1D }; soilProfile1D.Layers.Add(newLayer); } } // Add the newly created soil profile to the cache cachedSoilProfiles1D[x] = soilProfile1D; return soilProfile1D; } /// /// Returns a that represents this instance (either Name or SoilProfile1D). /// /// /// A that represents this instance. /// public override string ToString() { if (!string.IsNullOrEmpty(Name)) { return Name; } if (orgSoilProfile != null) { return orgSoilProfile.ToString(); } return "Soil Surface Profile with null Soil Profile"; } /// /// Converts to soil profile2D. /// /// public SoilProfile2D ConvertToSoilProfile2D() { var soilProfile2D = new SoilProfile2D { Geometry = Geometry }; soilProfile2D.Surfaces.AddRange(Surfaces); soilProfile2D.Name = Name; return soilProfile2D; } /// /// Updates the dike material. /// private void UpdateDikeMaterial() { if (soilProfile != null && SurfaceLine != null) { double topSurfaceLine = SurfaceLine.GetMaxZ(); if (!double.IsNaN(topSurfaceLine) && (soilProfile.Layers.Count == 0 || soilProfile.TopLevel < topSurfaceLine)) { double newTopLevel = topSurfaceLine + 0.5; if (soilProfile.Layers.Count > 0 && soilProfile.Layers[0].Soil == DikeEmbankmentMaterial) { SoilLayer1D dikeMaterialLayer = soilProfile.Layers[0]; dikeMaterialLayer.TopLevel = newTopLevel; } else { // Add toplayer of dikematerial var newLayer = new SoilLayer1D { TopLevel = newTopLevel, Soil = DikeEmbankmentMaterial, }; // special handling for dummy soil profiles if (soilProfile.Layers.Count == 0 && DikeEmbankmentMaterial == null) { soilProfile.BottomLevel = SurfaceLine.GetMinZ() - 1; } soilProfile.Layers.Insert(0, newLayer); soilProfile.EnsureLastLayerHasHeight(); } } } } /// /// Adds the layer geometry. /// /// The data. /// The layer. /// The minimum x. /// The maximum x. private static void AddLayerGeometry(GeometryData data, SoilLayer1D layer, double minX, double maxX) { var top = layer.TopLevel; var bottom = layer.BottomLevel; if (Math.Abs(layer.BottomLevel - layer.SoilProfile.BottomLevel) < GeometryConstants.Accuracy) { bottom = data.Bottom; } var bottomLeft = new Point2D(minX, bottom); var bottomRight = new Point2D(maxX,bottom); var topLeft = new Point2D(minX, top); var topRight = new Point2D(maxX, top); data.Points.Add(bottomLeft); data.Points.Add(bottomRight); data.Points.Add(topLeft); data.Points.Add(topRight); data.Curves.Add(new GeometryCurve(bottomLeft, bottomRight)); data.Curves.Add(new GeometryCurve(bottomRight, topRight)); data.Curves.Add(new GeometryCurve(topRight, topLeft)); data.Curves.Add(new GeometryCurve(topLeft, bottomLeft)); } private void AddSurfaceLineGeometry(GeometryData data) { var current = new Point2D(surfaceLine.Points[0].X, surfaceLine.Points[0].Z); data.Points.Add(current); for (int i = 1; i < surfaceLine.Points.Count; ++i) { var previous = current; current = new Point2D(surfaceLine.Points[i].X, surfaceLine.Points[i].Z); data.Points.Add(current); data.Curves.Add(new GeometryCurve(previous, current)); } } private void AddSettlementZones(GeometryData locGeometry) { if (surfaceLine2 != null && surfaceLine2.HasDike()) { var xToeRiver = surfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtRiver).X; AddVerticalAt(locGeometry, xToeRiver); var xTopRiver = surfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver).X; var xRiver = xToeRiver + (xTopRiver - xToeRiver) / 3.0; AddVerticalAt(locGeometry, xRiver); var xToePolder = surfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).X; var xTopPolder = surfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder).X; var xPolder = xTopPolder + 2 * (xToePolder - xTopPolder) / 3.0; AddVerticalAt(locGeometry, xPolder); AddVerticalAt(locGeometry, xToePolder); } } private void AddVerticalAt(GeometryData aGeometry, double x) { const double zMax = 100000.0; var topX = new Point2D(x, zMax); var bottomX = new Point2D(x, -zMax); aGeometry.Points.Add(topX); aGeometry.Points.Add(bottomX); aGeometry.Curves.Add(new GeometryCurve(topX, bottomX)); //aGeometry.NewlyEffectedCurves.Add(aGeometry.Curves.Last());##Bka } private void BuildGeometryModel() { if (surfaceLine == null || soilProfile == null || soilProfile.Layers.Count == 0 || surfaceLine.GetMaxZ() < soilProfile.BottomLevel || surfaceLine.Points.Count < 2) { return; } var bounds = SurfaceLine.GetGeometryBounds(); double minX = bounds.Left; double maxX = bounds.Right; Geometry.Clear(); Geometry.Left = minX; Geometry.Right = maxX; Geometry.Bottom = Math.Min(soilProfile.BottomLevel, surfaceLine.GetMinZ() - 1); // add profile geometry soilProfile.Layers.Sort(); foreach (var layer in soilProfile.Layers) { AddLayerGeometry(Geometry, layer, minX, maxX); } // add surface line geometry AddSurfaceLineGeometry(Geometry); // add the extra lines to create the settlementzones if required if (createSettlementZones) { AddSettlementZones(Geometry); } // Geometry.NewlyEffectedPoints.AddRange(Geometry.Points); // Geometry.NewlyEffectedCurves.AddRange(Geometry.Curves); // Geometry.RegenerateGeometry(); // Geometry.DeleteLooseCurves();##Bka } private void RebuildSurfaces(GeometryData locGeometry) { // Surfaces.Clear(); // if (locGeometry == null || surfaceLine == null) // { // return; // } // var gu = new GeotechnicsUtilities(); // gu.RemoveGeometryDataAboveSurfaceLine(ref locGeometry, surfaceLine); // foreach (var geometrySurface in locGeometry.Surfaces) // { // var bounds = geometrySurface.GetGeometryBounds(); // var z = (bounds.Top + bounds.Bottom) * 0.5; // // var soilLayer = soilProfile.GetLayerAt(z); // // if (soilLayer != null) // { // Surfaces.Add(new SoilLayer2D // { // GeometrySurface = geometrySurface, // IsAquifer = soilLayer.IsAquifer, // WaterpressureInterpolationModel = soilLayer.WaterpressureInterpolationModel, // Soil = soilLayer.Soil, // SoilProfile1D = this // }); // } // } ##Bka } /// /// Updates the layers. /// private void UpdateLayers() { // dirty = false; // initial = false; // // // Clear all cached soil profiles // cachedSoilProfiles1D.Clear(); // // if (orgSoilProfile != null) // { // soilProfile = (SoilProfile1D)orgSoilProfile.Clone(); // // UpdateDikeMaterial(); // BuildGeometryModel(); // RebuildSurfaces(Geometry); // } ##Bka } } }