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