Hello all.
We are using the ThinkGeo WPF 7.0 version.
I need an ability to snap to an existing polygon. I have seen the current samples. That doesn’t handle our exact issue. What we need is when the chooses to draw a line on the map, we need the cursor to snap to a given polygon. We have it working after the user has already added one vertex. What isn’t working is snapping for the first vertex.
It seems the MouseMoved event of the Map.TrackOverlay object will not fire until after the shape has already started (ie: user has chosen the first vertex for the line).
Is there a way for us to snap the cursor to the polygon before adding the first vertex?
SnapTo feature--need help
Hi Scott,
Are you using Map1.TrackOverlay.MouseMoved event? I think Map1.TrackOverlay.MapMouseMove can works for you.
Regards,
Don
Yes, that is the event I am using. I’ll try the MapMouseMove.
That is the event I needed. Thanks. The issue I have now is that the cursor is not moving to what I am trying to move it too.
After I get the correct coordinates I try setting the ScreenX & ScreenY properties on the InteractionArguments object of MapMouseMoveInteractiveOverlayEventArgs. However after I set that, no change appears to be made.
privatevoidMouseMoved(objectsender, MapMouseMoveInteractiveOverlayEventArgs e){try{if(Map.TrackOverlay.TrackMode == TrackMode.Circle || Map.TrackOverlay.TrackMode == TrackMode.Point)return;
if(!ViewModel.IsUsingTouch) CalculateDrawingDimensionsAndDisplay();if(!ViewModel.SnapOn || ViewModel.CurrentGeometryType == GeometryType.None || ViewModel.CurrentGeometryType == GeometryType.Circle)return;
LayerOverlay overlay;InMemoryFeatureLayer layer;switch(ViewModel.CurrentEditor){caseEditor.Design:overlay = (LayerOverlay)Map.Overlays[PROPOSAL_OVERLAY];layer = (InMemoryFeatureLayer)overlay.Layers[PROPOSAL_LAYER];break;default:overlay = (LayerOverlay)Map.Overlays[LAYOUT_OVERLAY];layer = (InMemoryFeatureLayer)overlay.Layers[LAYOUT_LAYER];break;}
layer.FeatureSource.Open();MapUtilities.SnapToFeature(e, layer.InternalFeatures, TOLERANCE, Map.MapUnit, Map);layer.FeatureSource.Close();}catch(Exception ex){LogHost.Default.Error(ex.ToString());}}publicstaticvoidSnapToFeature(MapMouseMoveInteractiveOverlayEventArgs e, GeoCollection features,floattolerance, GeographyUnit mapUnit, WpfMap map){try{var newMovedVertex =newVertex();var lowestDistance =double.MaxValue;
foreach(var featureinfeatures){switch(feature.GetShape().GetWellKnownType()){caseWellKnownType.Polygon:FindSnapToPointOnPolygon(e, mapUnit,refnewMovedVertex,reflowestDistance, feature.GetShape()asPolygonShape, map);break;}}if(!(lowestDistance <= tolerance))return;
var screenCoordinate = ExtentHelper.ToScreenCoordinate(map.CurrentExtent,newFeature(newMovedVertex), (float) map.CurrentExtent.Width, (float) map.CurrentExtent.Height);
e.InteractionArguments.ScreenX = screenCoordinate.X;e.InteractionArguments.ScreenY = screenCoordinate.Y;}catch(Exception ex){LogHost.Default.ErrorException(ex.ToString(), ex);}}
privatestaticvoidFindSnapToPointOnPolygon(MapMouseMoveInteractiveOverlayEventArgs e, GeographyUnit mapUnit,refVertex newMovedVertex,refdoublelowestDistance, PolygonShape polygon, WpfMap map){var polygonDistance =double.MaxValue;var nearestPoint =newPointShape();for(var i = 0; i < polygon.OuterRing.Vertices.Count - 1; i++){var line =new[] { polygon.OuterRing.Vertices, polygon.OuterRing.Vertices[i + 1] };var minx = polygon.OuterRing.Vertices.X > polygon.OuterRing.Vertices[i + 1].X ? polygon.OuterRing.Vertices[i + 1].X : polygon.OuterRing.Vertices.X;var maxx = polygon.OuterRing.Vertices.X < polygon.OuterRing.Vertices[i + 1].X ? polygon.OuterRing.Vertices[i + 1].X : polygon.OuterRing.Vertices.X;var miny = polygon.OuterRing.Vertices.Y > polygon.OuterRing.Vertices[i + 1].Y ? polygon.OuterRing.Vertices[i + 1].Y : polygon.OuterRing.Vertices.Y;var maxy = polygon.OuterRing.Vertices.Y < polygon.OuterRing.Vertices[i + 1].Y ? polygon.OuterRing.Vertices[i + 1].Y : polygon.OuterRing.Vertices.Y;
var screenPointF =newScreenPointF(e.InteractionArguments.ScreenX, e.InteractionArguments.ScreenY);var worldCoordinate = ExtentHelper.ToWorldCoordinate(map.CurrentExtent, screenPointF, (float)map.CurrentExtent.Width, (float)map.CurrentExtent.Height);var worldVertex =newVertex(worldCoordinate);if(((!(minx < worldVertex.X)) || (!(maxx > worldVertex.X))) &&((!(miny < worldVertex.Y)) || (!(maxy > worldVertex.Y))))continue;
var xLine =newLineShape(line);var newDistance = xLine.GetDistanceTo(newPointShape(worldVertex), mapUnit, DistanceUnit.Meter);if(!(polygonDistance > newDistance))continue;
polygonDistance = newDistance;nearestPoint = xLine.GetClosestPointTo(newPointShape(worldVertex), mapUnit);}if(!(polygonDistance < lowestDistance))return;
lowestDistance = polygonDistance;newMovedVertex =newVertex(nearestPoint.X, nearestPoint.Y);}
Hi Scott,
Sorry I miss some information about your question. I think maybe the new event cannot implement what you want, because you cannot set the mouse position via it.
Let us talk about this further, I think there are two possibilities about your scenario:
1. When you move mouse close to a polygon, the mouse cursor snap to the polygon.
2. When you move mouse close to a polygon, there is a point appear in the border of polygon for point out where can be the first snap point.
For item 1:
I think you have to call windows API SetCursorPos, because our API cannot move mouse cursor.
For item 2:
You can use currently MapMouseMove event and function, just need to draw a dynamic point on polygon when mouse move.
After this step, I think the customer still need to click on map for make sure where is the first point.
So now maybe you can call Map1.TrackOverlay.MouseClick to simulator click on target point and still use Map1.TrackOverlay.MouseMoved event for other points.
Please let me know whether it’s helpful for your scenario?
Regards,
Don