Index: src/Deltares.DSoilModel.Forms/Translations.xml =================================================================== diff -u -r67 -r84 --- src/Deltares.DSoilModel.Forms/Translations.xml (.../Translations.xml) (revision 67) +++ src/Deltares.DSoilModel.Forms/Translations.xml (.../Translations.xml) (revision 84) @@ -72,13 +72,13 @@ - + + - Index: src/Deltares.DSoilModel.Forms/DSoilModelMapEditor.cs =================================================================== diff -u -r6 -r84 --- src/Deltares.DSoilModel.Forms/DSoilModelMapEditor.cs (.../DSoilModelMapEditor.cs) (revision 6) +++ src/Deltares.DSoilModel.Forms/DSoilModelMapEditor.cs (.../DSoilModelMapEditor.cs) (revision 84) @@ -6,6 +6,7 @@ using Deltares.DSoilModel.Data; using Deltares.DSoilModel.Forms.Properties; using Deltares.Geographic; +using Deltares.Geometry; using Deltares.Geotechnics; using Deltares.Geotechnics.ConePenetrationTest; using Deltares.Standard; @@ -18,6 +19,7 @@ using Deltares.Standard.Reflection; using DevExpress.XtraBars; using DotSpatial.Controls; +using DotSpatial.Data; using DotSpatial.Symbology; using DotSpatial.Topology; @@ -66,9 +68,7 @@ splitSegmentButton = CreateButton(Resources.SplitSegment); BindSupport.Bind(panel, splitSegmentButton, me => me.SplitSegmentLocation()); - var splitSegmentMenuItem = new ToolStripMenuItem("Split Segment"); - mapEditor.ContextMenuStrip.Items.Add(splitSegmentMenuItem); - BindSupport.Bind(panel, splitSegmentMenuItem, ge => ge.SplitSegment()); + InitializeContextMenu(); BindSupport.Assign(panel, this); @@ -77,6 +77,17 @@ DataEventPublisher.OnAfterChange += DataEventPublisher_OnAfterChange; } + private void InitializeContextMenu() + { + var splitSegmentMenuItem = new ToolStripMenuItem("Split segment"); + mapEditor.ContextMenuStrip.Items.Add(splitSegmentMenuItem); + BindSupport.Bind(panel, splitSegmentMenuItem, ge => ge.SplitSegment()); + + var assignToSegmentMenuItem = new ToolStripMenuItem("Link to nearest segment"); + mapEditor.ContextMenuStrip.Items.Add(assignToSegmentMenuItem); + BindSupport.Bind(panel, assignToSegmentMenuItem, ge => ge.LinkToNearestSegment()); + } + /// /// Gets or sets the project (setting: Adding Layers from Project to MapEditor). /// @@ -169,20 +180,6 @@ } } - /// - /// Complete split segment operation (after setting a split location) - /// - public void SplitSegment() - { - if (splittingSegments.Any() && segmentSplitters.Any()) {} - { - var splitter = segmentSplitters[0]; - double x = GeographicHelper.Instance.GetOffsetOnGeographicLineString(splitter, splitter.SoilSegment); - ClearSegmentSplitter(); - project.SplitSoilSegment(splitter.SoilSegment, x); - UndoRedoManager.Instance.EndAction(); - } - } /// /// Zoom out the map to display all data. @@ -208,6 +205,18 @@ } return false; } + if (property == this.GetMemberName(x => x.LinkToNearestSegment())) + { + // segments present and at least one CPT or boring must be selected + if (project != null && project.SoilSegments.Count > 0 && mapEditor.SelectedObjects != null && mapEditor.SelectedObjects.Count > 0) + { + if (mapEditor.SelectedObjects.Any(o => o is ConePenetrationTestData || o is Boring)) + { + return true; + } + } + return false; + } else { return true; @@ -259,6 +268,132 @@ } /// + /// Complete split segment operation (after setting a split location) + /// + private void SplitSegment() + { + if (splittingSegments.Any() && segmentSplitters.Any()) + { + var splitter = segmentSplitters[0]; + double x = GeographicHelper.Instance.GetOffsetOnGeographicLineString(splitter, splitter.SoilSegment); + ClearSegmentSplitter(); + project.SplitSoilSegment(splitter.SoilSegment, x); + UndoRedoManager.Instance.EndAction(); + } + } + + /// + /// Link all selected CPT's and or Borings to the nearest (selected) segment(s) + /// + private void LinkToNearestSegment() + { + // objects to link + var cpts = mapEditor.SelectedObjects.Where(o => o is ConePenetrationTestData).Cast().ToList(); + var borings = mapEditor.SelectedObjects.Where(o => o is Boring).Cast().ToList(); + var segments = mapEditor.SelectedObjects.Where(o => o is SoilSegment).Cast().ToList(); + if (segments.Count == 0) + { + segments = project.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) < Geometry.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; + } + + + /// /// Selection change handler for specific interactions /// /// Selected object