using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using System.Xml.Serialization;
using Deltares.DSoilModel.Data;
using Deltares.DSoilModel.Forms.Properties;
using Deltares.Geometry;
using Deltares.Geometry.Forms;
using Deltares.Geotechnics;
using Deltares.Geotechnics.ConePenetrationTest;
using Deltares.Geotechnics.Forms;
using Deltares.Geotechnics.GeotechnicalGeometry;
using Deltares.Standard;
using Deltares.Standard.EventPublisher;
using Deltares.Standard.Extensions;
using Deltares.Standard.Forms;
using Deltares.Standard.Forms.DExpress;
using Deltares.Standard.Language;
using Deltares.Standard.Reflection;
namespace Deltares.DSoilModel.Forms
{
///
/// Class to be able to show a soilsegment as length profile (based on a fictive 2D profile with the length of the segment)
/// In the length profile, the mapped CPTs and Borings belonging to the segment are shown.
///
public class DSoilModelSegmentGeometryEditor : IVisibleEnabled, IDisposable
{
private readonly List boringLookup2Ds = new List();
private readonly List cptLookup2Ds = new List();
private readonly GeometryEditor geometryEditor;
private readonly Panel panel = new Panel();
private readonly SpatialEditor spatialEditor;
private DSoilModelProject project;
private SoilProfile2D selectedProfile2D;
private SoilSegment selectedSegment;
private SoilSegmentSplitLocation splitLocation;
///
/// Initializes a new instance of the class.
///
/// The main form to be able to set the caption of the geometry dock panel.
public DSoilModelSegmentGeometryEditor(GeometryEditor geometryEditor)
{
this.geometryEditor = geometryEditor;
geometryEditor.SurpressSpatialSelection = true;
spatialEditor = geometryEditor.SpatialEditor;
spatialEditor.RegisterShapeType(typeof(GeometryData), typeof(DrawingGeometry), null, null, null, false);
spatialEditor.RegisterShapeType(typeof(GeometryPoint), typeof(DrawingPoint), null, null, null, false);
spatialEditor.RegisterShapeType(typeof(GeometryCurve), typeof(DrawingLine), null, null, null, false);
spatialEditor.RegisterShapeType(typeof(GeometryPointString), typeof(DrawingPointString), null, null, null, false);
spatialEditor.RegisterShapeType(typeof(LocalizedGeometryPointString), typeof(DrawingLocalisedGeometryPointString), null, null, null, false);
spatialEditor.RegisterShapeType(typeof(ConePenetrationTestLookup2D), typeof(DrawingCPT), null, null, null, false);
spatialEditor.RegisterShapeType(typeof(BoringLookup2D), typeof(DrawingBoring), null, null, null, false);
spatialEditor.RegisterShapeType(typeof(BoringLayer), typeof(DrawingBoringLayer), null, null, null, false);
spatialEditor.RegisterShapeType(typeof(SoilSegmentSplitLocation), typeof(DrawingSoilSegmentSplitLocation));
spatialEditor.MarginBottom = 55;
foreach (ShapeInfo shapeInfo in spatialEditor.ShapeInfos)
{
shapeInfo.AllowSelect = shapeInfo.AllowEdit;
}
spatialEditor.ShapeRemoved += spatialEditor_ShapeRemoved;
DataEventPublisher.OnSelectionChanged += DataEventPublisherOnSelectionChanged;
DataEventPublisher.OnAfterChange += DataEventPublisherOnOnAfterChange;
DataEventPublisher.OnDataListModified += DataEventPublisherOnOnDataListModified;
AddUiItems();
}
///
/// Gets the spatial editor.
///
///
/// The spatial editor.
///
public SpatialEditor SpatialEditor
{
get
{
return spatialEditor;
}
}
///
/// Gets or sets the project.
///
public DSoilModelProject Project
{
get
{
return project;
}
set
{
if (value != project)
{
spatialEditor.Clear();
}
project = value;
}
}
///
/// Gets or sets the onselectionchanged callback.
///
///
/// The is visible callback.
///
[XmlIgnore]
[Browsable(false)]
public Func AddCPTCallback { get; set; }
///
/// Gets or sets the is visible callback.
///
///
/// The is visible callback.
///
[XmlIgnore]
[Browsable(false)]
public Func IsVisibleCallback { get; set; }
///
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
///
public void Dispose()
{
spatialEditor.ShapeRemoved -= spatialEditor_ShapeRemoved;
DataEventPublisher.OnAfterChange -= DataEventPublisherOnOnAfterChange;
DataEventPublisher.OnSelectionChanged -= DataEventPublisherOnSelectionChanged;
DataEventPublisher.OnDataListModified -= DataEventPublisherOnOnDataListModified;
}
///
/// Determines whether the specified property is visible.
///
/// The property.
///
public bool IsVisible(string property)
{
return true;
}
///
/// Determines whether the specified property is enabled.
///
/// The property.
///
public bool IsEnabled(string property)
{
switch (property)
{
case "SplitSegment":
return splitLocation != null;
case "SplitSegmentLocation":
return splitLocation == null && selectedSegment != null;
}
return true;
}
///
/// Property for binding of Split segment toolbar button.
/// So even when it seems not used, it is used!
///
///
/// true if [split segment location]; otherwise, false.
///
private bool SplitSegmentLocation
{
get
{
return false;
}
set
{
AddSoilSegmentSplitLocation();
}
}
private void AddSoilSegmentSplitLocation(SoilSegmentSplitLocation splitter = null)
{
if (spatialEditor.EmptySelection != null && spatialEditor.EmptySelection.DataObject is SoilProfile2D)
{
DataEventPublisher.InvokeWithoutPublishingEvents(() =>
{
var soilProfile2D = spatialEditor.EmptySelection.DataObject as SoilProfile2D;
if (splitter == null)
{
splitLocation = new SoilSegmentSplitLocation
{
SoilSegment = selectedSegment,
SoilProfile2D = soilProfile2D,
XCoordinate = (soilProfile2D.Geometry.Right - soilProfile2D.Geometry.Left) * 0.5
};
}
else
{
splitLocation = splitter;
splitLocation.SoilProfile2D = soilProfile2D;
}
if (splitLocation.SoilSegment != selectedSegment)
{
ShowSoilSegment(splitLocation.SoilSegment, false);
}
});
UndoRedoManager.Instance.BeginAction();
spatialEditor.AddObject(splitLocation);
spatialEditor.Refresh();
DataEventPublisher.AfterChange(this);
// event to trigger the map editor
DataEventPublisher.SelectionChanged(splitLocation);
}
}
private void DataEventPublisherOnOnAfterChange(object sender, PublishEventArgs publishEventArgs)
{
if (selectedSegment != null && selectedProfile2D != null)
{
if (sender is ConePenetrationTestPerSegment || sender is BoringPerSegment)
{
ShowSoilSegment(selectedSegment, true);
}
}
var segment = sender as SoilSegment;
if (segment != null)
{
ShowSoilSegment(segment, selectedProfile2D != null);
}
if (ReferenceEquals(sender, spatialEditor) && publishEventArgs.Property == spatialEditor.GetMemberName(x => x.InsertType))
{
DataEventPublisher.AfterChange(this);
}
}
private void DataEventPublisherOnSelectionChanged(object sender, PublishEventArgs e)
{
selectedProfile2D = null;
if (sender is SoilSegment)
{
var segment = (SoilSegment) sender;
if (segment != selectedSegment)
{
ShowSoilSegment(sender, false);
}
}
else if (sender is SoilSegmentSplitLocation)
{
// split going on in map window ?
if (sender != splitLocation)
{
if (splitLocation != null)
{
spatialEditor.RemoveObject(splitLocation);
}
var splitter = sender as SoilSegmentSplitLocation;
if (splitter.SoilSegment != selectedSegment)
{
ShowSoilSegment(splitter.SoilSegment, false);
}
AddSoilSegmentSplitLocation(splitter);
}
}
}
private void DataEventPublisherOnOnDataListModified(object sender, PublishEventArgs publishEventArgs)
{
if (selectedSegment != null && selectedProfile2D != null)
{
if (sender is List || sender is List)
{
ShowSoilSegment(selectedSegment, true);
}
}
else if (sender is List)
{
// end split segment operation ?
if (splitLocation != null)
{
var dataListModifiedArgs = publishEventArgs as DataListModifiedArgs;
if (dataListModifiedArgs != null && dataListModifiedArgs.Action == ListModifyAction.Delete)
{
spatialEditor.RemoveObject(splitLocation);
splitLocation = null;
DataEventPublisher.AfterChange(this);
}
}
}
}
private void ShowSoilSegment(object sender, bool forceUpdate)
{
var segment = (SoilSegment)sender;
if (segment.StochasticSoilModel != null
&& segment.StochasticSoilModel.StochasticSoilProfiles != null
&& segment.StochasticSoilModel.StochasticSoilProfiles.Count > 0)
{
ShowSoilProfile2D(sender, forceUpdate);
}
geometryEditor.Title = string.Format(LocalizationManager.GetTranslatedText(this, "ShowSegmentLengthProfile"), segment.Name);
selectedSegment = segment;
splitLocation = null;
DataEventPublisher.AfterChange(this);
}
private void ShowSoilProfile2D(object sender, bool forceUpdate)
{
var segment = (SoilSegment) sender;
DataEventPublisher.InvokeWithoutPublishingEvents(() =>
{
if (selectedProfile2D == null)
{
var soilProfile2D = new SoilProfile2D
{
Geometry = CreateGeometryForSegment(segment),
Name = segment.Name
};
selectedProfile2D = soilProfile2D;
selectedProfile2D.Name = "";
}
if (spatialEditor.EmptySelection == null
|| spatialEditor.EmptySelection.DataObject == null
|| !(spatialEditor.EmptySelection.DataObject is SoilProfile2D)
|| (spatialEditor.EmptySelection.DataObject as SoilProfile2D).Name != selectedProfile2D.Name || forceUpdate)
//|| (spatialEditor.EmptySelection.DataObject as SoilProfile2D).Name != selectedSegment.Name)
{
selectedProfile2D.Name = segment.Name;
Clear();
geometryEditor.InsertShapeMethod = selectedProfile2D.Geometry.CreateGeometryObject;
AddSoilProfile2D(selectedProfile2D);
var bottomCptsBorings = AddCptAndBoringLookUpsFromSegment(segment, selectedProfile2D);
selectedProfile2D.Geometry.Bottom = Math.Min(selectedProfile2D.Geometry.Bottom, bottomCptsBorings - 5);
spatialEditor.EmptySelection = new EmptyShape(selectedProfile2D);
spatialEditor.Refresh();
spatialEditor.ZoomToExtents(false);
}
});
}
private GeometryData CreateGeometryForSegment(SoilSegment segment)
{
var geometry = new GeometryData();
var point1 = new GeometryPoint(0, 0, 0);
var point2 = new GeometryPoint(segment.GetSegmentLength(), 0, 0);
geometry.Left = point1.X;
geometry.Right = point2.X;
geometry.Bottom = GeometryConstants.DefaultBottomLimitGeometry;
var curve1 = new GeometryCurve(point1, point2);
geometry.Points.AddRange(new[]
{
point1, point2
});
geometry.Curves.Add(curve1);
geometry.Name = segment.Name;
return geometry;
}
private void AddSoilProfile2D(SoilProfile2D soilProfile)
{
spatialEditor.AddObject(soilProfile);
spatialEditor.AddObject(soilProfile.Geometry);
spatialEditor.AddList(soilProfile.Surfaces);
spatialEditor.AddList(soilProfile.Geometry.Curves);
spatialEditor.AddList((IList) soilProfile.Geometry.Points);
if (splitLocation != null)
{
spatialEditor.AddObject(splitLocation);
}
selectedProfile2D = soilProfile;
}
private double AddCptAndBoringLookUpsFromSegment(SoilSegment segment, SoilProfile2D soilProfile2D)
{
var bottom = double.MaxValue;
DataEventPublisher.InvokeWithoutPublishingEvents(() =>
{
cptLookup2Ds.Clear();
segment.SetXlocalForCpts();
foreach (var cptPerSegment in segment.Cpts)
{
if (cptPerSegment.ConePenetrationTestData != null)
{
var cptLookup = new ConePenetrationTestLookup2D
{
ConePenetrationTestData = cptPerSegment.ConePenetrationTestData, Xlocal = cptPerSegment.Xlocal, SoilProfile2D = soilProfile2D
};
cptLookup2Ds.Add(cptLookup);
bottom = Math.Min(bottom, cptLookup.ConePenetrationTestData.Bottom);
}
}
spatialEditor.AddList(cptLookup2Ds);
boringLookup2Ds.Clear();
segment.SetXlocalForBorings();
foreach (var boringPerSegment in segment.Borings)
{
if (boringPerSegment.Boring != null)
{
var boringLookup = new BoringLookup2D
{
Boring = boringPerSegment.Boring, Xlocal = boringPerSegment.Xlocal, SoilProfile2D = soilProfile2D
};
boringLookup2Ds.Add(boringLookup);
bottom = Math.Min(bottom, boringLookup.Boring.Bottom);
}
}
spatialEditor.AddList(boringLookup2Ds);
});
return bottom;
}
private void Clear()
{
geometryEditor.Clear();
cptLookup2Ds.Clear();
boringLookup2Ds.Clear();
splitLocation = null;
}
private void AddUiItems()
{
// Add button to be able to insert a segment split location
var splitButton = geometryEditor.CreateButton(Resources.SplitSegment);
splitButton.Caption = LocalizationManager.GetTranslatedText(this, "SplitSegmentLocation");
BindSupport.Bind(panel, splitButton, typeof(DSoilModelSegmentGeometryEditor), "SplitSegmentLocation");
// Add popup context menu for performing the actual split action
var splitSegmentMenuItem = new ToolStripMenuItem("Split Segment");
spatialEditor.ContextMenuStrip.Items.Add(splitSegmentMenuItem);
BindSupport.Bind(panel, splitSegmentMenuItem, ge => ge.SplitSegment());
BindSupport.Assign(panel, this);
}
private void SplitSegment()
{
if (selectedSegment != null && splitLocation != null)
{
project.SplitSoilSegment(selectedSegment, splitLocation.XCoordinate);
splitLocation = null;
UndoRedoManager.Instance.EndAction();
}
}
private void spatialEditor_ShapeRemoved(object sender, ShapeEventArgs e)
{
object dataObject = e.Shape.DataObject;
if (dataObject is SoilSegmentSplitLocation)
{
splitLocation = null;
// mimic the communication from the map editor to indicate that the splitter was deleted
DataEventPublisher.DataListModified(new List(), ListModifyAction.Delete);
DataEventPublisher.AfterChange(this);
}
}
}
}