FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

MW5CORE-254 Adding CAD-like snapping pluging · MapWindow/MapWindow5@f938cfa · GitHub

Repository navigation

Commit f938cfa

Browse files
committed
MW5CORE-254 Adding CAD-like snapping pluging
1 parent bc13030 commit f938cfa

46 files changed

Lines changed: 3490 additions & 107 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
using MW5.Plugins.AdvancedSnapping.Services;
2+
using MW5.Plugins.AdvancedSnapping.Context;
3+
using MW5.Plugins.AdvancedSnapping.Listeners;
4+
using MW5.Plugins.AdvancedSnapping.Views;
5+
using MW5.Plugins.Concrete;
6+
using MW5.Plugins.Interfaces;
7+
using MW5.Plugins.Mef;
8+
using MW5.Plugins.Mvp;
9+
using MW5.Plugins.ShapeEditor.Context;
10+
using System.Collections.Generic;
11+
using System.Windows;
12+
13+
namespace MW5.Plugins.AdvancedSnapping
14+
{
15+
[MapWindowPlugin(loadOnStartUp: true, After = new[] { "Shape Editor" })]
16+
public class AdvancedSnappingPlugin : BasePlugin
17+
{
18+
#region private variables
19+
private IAppContext _context;
20+
private IAnchorService _anchorService;
21+
private ISnapRestrictionService _snapRestrictionService;
22+
#endregion
23+
24+
#region Properties:
25+
public bool CanSnapPerpendicular
26+
{
27+
get => _anchorService.ReferenceSegment != null;
28+
}
29+
30+
public bool CanSnapParallel
31+
{
32+
get => _anchorService.ReferenceSegment != null;
33+
}
34+
35+
public bool CanSnapBearing
36+
{
37+
get => true;
38+
}
39+
40+
public bool CanSnapDistance
41+
{
42+
get => true;
43+
}
44+
45+
public bool HasActiveSnapLines
46+
{
47+
get => _snapRestrictionService.HasActiveRestrictions;
48+
}
49+
50+
public bool AutoClearSnapLines
51+
{
52+
get => _snapRestrictionService.AutoClear;
53+
}
54+
55+
#endregion
56+
57+
#region Initialization
58+
59+
public override void Initialize(IAppContext context)
60+
{
61+
_context = context;
62+
63+
WPFWorkArounds();
64+
65+
IApplicationContainer container = context.Container;
66+
container.GetInstance<ContextMenuExtender>();
67+
container.GetInstance<ContextMenuView>();
68+
container.GetInstance<MapListener>();
69+
_anchorService = container.GetSingleton<IAnchorService>();
70+
_snapRestrictionService = container.GetSingleton<ISnapRestrictionService>();
71+
}
72+
73+
protected override void RegisterServices(IApplicationContainer container)
74+
{
75+
CompositionRoot.Compose(container);
76+
}
77+
78+
internal void WPFWorkArounds()
79+
{
80+
// Makes sure we have a WPF application, windows forms app does not initialize this for us:
81+
WindowExtensions.MainWindowHandle = _context.View.MainForm.Handle;
82+
83+
WindowExtensions.EnsureApplicationResources();
84+
85+
if (null == Application.Current)
86+
{
87+
var app = new Application();
88+
System.Windows.Forms.Application.EnableVisualStyles();
89+
}
90+
}
91+
92+
#endregion
93+
94+
#region Plugin settings
95+
96+
public override void SetSettings(IDictionary<string, string> settings)
97+
{
98+
base.SetSettings(settings);
99+
if (settings.TryGetValue("AutoClearSnapLines", out string autoClearSnapLines))
100+
_snapRestrictionService.AutoClear = bool.Parse(autoClearSnapLines);
101+
}
102+
103+
public override IDictionary<string, string> GetSettings()
104+
{
105+
var settings = base.GetSettings();
106+
settings["AutoClearSnapLines"] = AutoClearSnapLines.ToString();
107+
return settings;
108+
}
109+
110+
#endregion
111+
112+
}
113+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using MW5.Plugins.AdvancedSnapping.Context;
2+
using MW5.Plugins.AdvancedSnapping.Listeners;
3+
using MW5.Plugins.AdvancedSnapping.Services;
4+
using MW5.Plugins.Mvp;
5+
6+
namespace MW5.Plugins.AdvancedSnapping
7+
{
8+
internal static class CompositionRoot
9+
{
10+
public static void Compose(IApplicationContainer container)
11+
{
12+
container
13+
.RegisterSingleton<ISnapRestrictionService, SnapRestrictionService>()
14+
.RegisterSingleton<IAnchorService, AnchorService>()
15+
.RegisterSingleton<IDrawingService, DrawingService>()
16+
.RegisterSingleton<ContextMenuExtender>()
17+
.RegisterSingleton<MapListener>();
18+
19+
}
20+
}
21+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace MW5.Plugins.AdvancedSnapping.Context
2+
{
3+
public enum AdvancedSnappingCommand
4+
{
5+
None = 0,
6+
SnapParallel = 1,
7+
SnapPerpendicular = 2,
8+
SnapBearing = 3,
9+
10+
SnapDistance = 10,
11+
12+
ClearSnapLines = 20,
13+
AutoClearSnapLines = 21
14+
}
15+
}
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Drawing;
4+
using System.Linq;
5+
using System.Windows.Forms;
6+
using MW5.Api.Enums;
7+
using MW5.Plugins.Interfaces;
8+
using MW5.Plugins.Mvp;
9+
using MW5.Plugins.AdvancedSnapping.Services;
10+
using MW5.Api.Interfaces;
11+
12+
namespace MW5.Plugins.AdvancedSnapping.Context
13+
{
14+
public class ContextMenuExtender : CommandDispatcher<ShapeEditor.Context.ContextMenuView, AdvancedSnappingCommand>
15+
{
16+
private readonly IAppContext _context;
17+
private readonly AdvancedSnappingPlugin _plugin;
18+
private readonly ShapeEditor.Context.ContextMenuPresenter _shapeEditorContextMenuPresenter;
19+
private readonly ISnapRestrictionService _snapRestrictionService;
20+
private readonly IAnchorService _anchorService;
21+
22+
public bool IsOpen
23+
{
24+
get => _shapeEditorContextMenuPresenter.VertexMenu.Visible;
25+
}
26+
27+
public ContextMenuExtender(IAppContext context,
28+
AdvancedSnappingPlugin plugin,
29+
ShapeEditor.Context.ContextMenuView view,
30+
ISnapRestrictionService snapRestrictionService,
31+
IAnchorService anchorService,
32+
ShapeEditor.Context.ContextMenuPresenter shapeEditorContextMenuPresenter) : base(view)
33+
{
34+
_context = context ?? throw new ArgumentNullException("context");
35+
_plugin = plugin ?? throw new ArgumentNullException("plugin");
36+
_shapeEditorContextMenuPresenter = shapeEditorContextMenuPresenter ?? throw new ArgumentNullException("shapeEditorContextMenuPresenter");
37+
_snapRestrictionService = snapRestrictionService ?? throw new ArgumentNullException("snapRestrictionService");
38+
_anchorService = anchorService ?? throw new ArgumentNullException("anchorService");
39+
40+
AddItems();
41+
}
42+
43+
public void UpdateStates()
44+
{
45+
foreach (var item in items)
46+
item.Visible = false;
47+
48+
var layer = _context.Map.Layers.Current;
49+
if (!layer?.FeatureSet?.InteractiveEditing ?? true)
50+
return;
51+
52+
foreach (var item in items)
53+
{
54+
item.Enabled = false;
55+
switch (item.Name)
56+
{
57+
case "ctxSnapBearing":
58+
item.Enabled = _plugin.CanSnapBearing;
59+
item.Visible = item.Enabled;
60+
break;
61+
case "ctxSnapDistance":
62+
item.Enabled = _plugin.CanSnapDistance;
63+
item.Visible = item.Enabled;
64+
break;
65+
case "ctxSnapParallel":
66+
item.Enabled = _plugin.CanSnapParallel;
67+
item.Visible = item.Enabled;
68+
break;
69+
case "ctxSnapPerpendicular":
70+
item.Enabled = _plugin.CanSnapPerpendicular;
71+
item.Visible = item.Enabled;
72+
break;
73+
case "ctxClearSnapLines":
74+
item.Enabled = _plugin.HasActiveSnapLines;
75+
item.Visible = item.Enabled;
76+
break;
77+
case "ctxAutoClearSnapLines":
78+
item.Checked = _plugin.AutoClearSnapLines;
79+
item.Enabled = item.Visible = true;
80+
break;
81+
}
82+
}
83+
}
84+
85+
/// <summary>
86+
/// Adds context menu items to the shape editor
87+
/// </summary>
88+
private void AddItems()
89+
{
90+
// Keep track of items
91+
items = new List<ToolStripMenuItem>();
92+
93+
// Add them to the existing context menu
94+
var index = _shapeEditorContextMenuPresenter.VertexMenu.Items.IndexOfKey("ctxSnapping");
95+
index = AddItem(index, "ctxSnapParallel", "Parallel to this", "S", MW5.Plugins.AdvancedSnapping.Properties.Resources.parallel);
96+
index = AddItem(index, "ctxSnapPerpendicular", "Perpendicular to this", "F", MW5.Plugins.AdvancedSnapping.Properties.Resources.perpendicular);
97+
index = AddItem(index, "ctxSnapDistance", "Distance from this", "D", MW5.Plugins.AdvancedSnapping.Properties.Resources.distance);
98+
index = AddItem(index, "ctxSnapBearing", "Bearing from this", "G", MW5.Plugins.AdvancedSnapping.Properties.Resources.bearing);
99+
100+
// Put this one at the bottom
101+
index = _shapeEditorContextMenuPresenter.VertexMenu.Items.IndexOfKey("ctxClearEditor");
102+
index = AddItem(index, "ctxClearSnapLines", "Clear snap lines", "", null);
103+
104+
var options = _shapeEditorContextMenuPresenter.VertexMenu.Items["ctxSnapping"] as ToolStripMenuItem;
105+
var ctxAutoClearSnapLines = new ToolStripMenuItem {
106+
Name = "ctxAutoClearSnapLines",
107+
Text = "Auto-clear snap lines"
108+
};
109+
options.DropDownItems.Add(ctxAutoClearSnapLines);
110+
items.Add(ctxAutoClearSnapLines);
111+
112+
// Call this to hook up event handlers:
113+
InitMenu(new ToolStripItemCollection(_shapeEditorContextMenuPresenter.VertexMenu, items.ToArray()));
114+
}
115+
116+
private IList<ToolStripMenuItem> items;
117+
118+
private int AddItem(int index, string name, string text, string shortCutKey, Bitmap image)
119+
{
120+
var item = new ToolStripMenuItem();
121+
item.Name = name;
122+
item.Text = text;
123+
item.ShortcutKeyDisplayString = shortCutKey;
124+
if (image != null) item.Image = image;
125+
_shapeEditorContextMenuPresenter.VertexMenu.Items.Insert(index++, item);
126+
items.Add(item);
127+
return index;
128+
}
129+
130+
public override void RunCommand(AdvancedSnappingCommand command)
131+
{
132+
133+
var anchor = _anchorService.PrimaryAnchor;
134+
var userAnchorLocation = _anchorService.UserAnchorLocation;
135+
var segment = _anchorService.ReferenceSegment;
136+
137+
var map = _context.Map;
138+
switch (command)
139+
{
140+
case AdvancedSnappingCommand.ClearSnapLines:
141+
_snapRestrictionService.Clear();
142+
break;
143+
case AdvancedSnappingCommand.SnapDistance:
144+
_snapRestrictionService.SnapDistance(anchor, handle: map.GeometryEditor.NumPoints);
145+
break;
146+
case AdvancedSnappingCommand.SnapBearing:
147+
_snapRestrictionService.SnapBearing(anchor, handle: map.GeometryEditor.NumPoints);
148+
break;
149+
case AdvancedSnappingCommand.SnapParallel:
150+
if (segment != null)
151+
{
152+
// If we're snapping parallel, ask user how far if he's not yet digitizing
153+
//bool needsUserInput = (anchor == _anchorFeatureService.LastUserLocation);
154+
_snapRestrictionService.SnapParallel(
155+
_context.Map.GeometryEditor.NumPoints > 0 ? anchor : segment.Item1,
156+
segment.Item1, segment.Item2,
157+
offsetAnchor: _context.Map.GeometryEditor.NumPoints > 0 ? segment.Item1 : null,
158+
handle: map.GeometryEditor.NumPoints
159+
);
160+
}
161+
break;
162+
case AdvancedSnappingCommand.SnapPerpendicular:
163+
if (segment != null)
164+
{
165+
// If we're snapping parallel, ask user how far if he's not yet digitizing
166+
//bool needsUserInput = (anchor == _anchorService.LastUserLocation);
167+
_snapRestrictionService.SnapPerpendicular(
168+
anchor,
169+
segment.Item1, segment.Item2,
170+
handle: map.GeometryEditor.NumPoints
171+
);
172+
}
173+
break;
174+
case AdvancedSnappingCommand.AutoClearSnapLines:
175+
_snapRestrictionService.AutoClear = !_snapRestrictionService.AutoClear;
176+
UpdateStates();
177+
break;
178+
}
179+
180+
_context.View.Update();
181+
_context.Map.Redraw(RedrawType.SkipDataLayers);
182+
}
183+
}
184+
}

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL