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 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. /// /// /// 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); } } } }