ThinkGeo Cloud
ThinkGeo UI Controls
ThinkGeo Open Source
Help and Support
External Resources
ThinkGeo Cloud
ThinkGeo UI Controls
ThinkGeo Open Source
Help and Support
External Resources
using System; using System.Collections.ObjectModel; using System.Diagnostics; using System.Drawing; using System.Linq; using System.Windows.Forms; using ThinkGeo.MapSuite.Core; using ThinkGeo.MapSuite.DesktopEdition; public partial class Sample : Form { private Proj4Projection proj = new Proj4Projection(); private SnapToLayerEditInteractiveOverlay snapToLayerEditInteractiveOverlay = null; private double tolerance = 500; public Sample() { InitializeComponent(); winformsMap1.MapUnit = GeographyUnit.Meter; winformsMap1.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; proj.InternalProjectionParametersString = ManagedProj4Projection.GetWgs84ParametersString(); proj.ExternalProjectionParametersString = ManagedProj4Projection.GetSphericalMercatorParametersString(); GraticuleAdornmentLayer graticuleAdornmentLayer = new GraticuleAdornmentLayer(); graticuleAdornmentLayer.GraticuleLineStyle.OuterPen.Color = GeoColor.FromArgb(125, GeoColor.StandardColors.White); graticuleAdornmentLayer.GraticuleTextFont = new GeoFont("Arial", 8, DrawingFontStyles.Bold); graticuleAdornmentLayer.Projection = proj; winformsMap1.AdornmentOverlay.Layers.Add("graticule", graticuleAdornmentLayer); winformsMap1.CurrentExtent = new RectangleShape(500000, 3100000, 600000, 3000000); snapToLayerEditInteractiveOverlay = CreateSnapToGrid(winformsMap1, 2000, 2000, proj, tolerance); winformsMap1.Refresh(); } public static SnapToLayerEditInteractiveOverlay CreateSnapToGrid(WinformsMap winformsMap, Double inline, Double crossLine, Proj4Projection proj4Projection, double snapTolerance) { RectangleShape boundaryBox = winformsMap.CurrentExtent; boundaryBox.ScaleDown(80); PointShape startCorner = boundaryBox.UpperLeftPoint; //inMemoryFeatureLayer used to be snapped to. InMemoryFeatureLayer snappingGridLayer = new InMemoryFeatureLayer(); snappingGridLayer.ZoomLevelSet.ZoomLevel01.DefaultPointStyle = PointStyles.CreateSimplePointStyle(PointSymbolType.Cross, GeoColor.StandardColors.Black, GeoColor.StandardColors.Black, 1, 4); snappingGridLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20; double boxWidth = boundaryBox.Width; double boxHeight = boundaryBox.Height; for (double i = 0; i <= boxHeight; i = i + crossLine) { for (double j = 0; j <= boxWidth; j = j + inline) { PointShape newPoint = new PointShape(startCorner.X, startCorner.Y); // Now add j to the Y value. newPoint.X += j; newPoint.Y -= i; snappingGridLayer.InternalFeatures.Add(new Feature(newPoint)); } } // SnapToLayerEditInteractiveOverlay to snap dragged control point to nearest point of layer if within tolerance. SnapToLayerEditInteractiveOverlay snapToLayerEditInteractiveOverlay = new SnapToLayerEditInteractiveOverlay(); snapToLayerEditInteractiveOverlay.EditShapesLayer.InternalFeatures.Clear(); LayerOverlay snappingGridOverlay = new LayerOverlay(); snappingGridOverlay.Layers.Add("SnappingGrid", snappingGridLayer); snappingGridOverlay.Name = "SnappingGridOverlay"; winformsMap.Overlays.Add("SnappingGridOverlay", snappingGridOverlay); //Sets the PointStyle for the non dragged control points. snapToLayerEditInteractiveOverlay.ControlPointStyle = new PointStyle(PointSymbolType.Circle, new GeoSolidBrush(GeoColor.StandardColors.PaleGoldenrod), new GeoPen(GeoColor.StandardColors.Black), 8); //Sets the PointStyle for the dragged control points. snapToLayerEditInteractiveOverlay.DraggedControlPointStyle = new PointStyle(PointSymbolType.Circle, new GeoSolidBrush(GeoColor.StandardColors.Red), new GeoPen(GeoColor.StandardColors.Orange, 2), 8); snapToLayerEditInteractiveOverlay.ToSnapInMemoryFeatureLayer = snappingGridLayer; //Example using World coordinates for tolerance. snapToLayerEditInteractiveOverlay.ToleranceType = ToleranceCoordinates.World; snapToLayerEditInteractiveOverlay.Tolerance = (float)snapTolerance; snapToLayerEditInteractiveOverlay.ToleranceUnit = DistanceUnit.Meter; snapToLayerEditInteractiveOverlay.CalculateAllControlPoints(); winformsMap.EditOverlay = snapToLayerEditInteractiveOverlay; winformsMap.Refresh(); return snapToLayerEditInteractiveOverlay; } private void SwitchDrawingMode(object sender) { // Initialize a new track layer because ... // Clearing the overlays isn't enough, we have to basically recreate the layer SnapToLayerTrackInteractiveOverlay track = new SnapToLayerTrackInteractiveOverlay(); // The Track Layer Style Color baseColor = Color.Blue; GeoColor geoBaseColor = new GeoColor(175, baseColor.R, baseColor.G, baseColor.B); track.TrackShapeLayer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = AreaStyles.CreateSimpleAreaStyle(geoBaseColor, geoBaseColor, 2); track.TrackShapeLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20; winformsMap1.TrackOverlay = track; string buttonLabel = ((Button)sender).Text; track.TrackStarting += track_TrackStarting; track.TrackEnding += track_TrackEnding; track.TrackEnded += track_TrackEnded; track.VertexAdding += track_VertexAdding; switch (buttonLabel.ToUpper()) { case "POINT": winformsMap1.TrackOverlay.TrackMode = TrackMode.Point; track.TrackStarting -= track_TrackStarting; track.VertexAdding -= track_VertexAdding; break; case "LINE": winformsMap1.TrackOverlay.TrackMode = TrackMode.StraightLine; break; case "RECTANGLE": winformsMap1.TrackOverlay.TrackMode = TrackMode.Rectangle; break; case "POLYGON": winformsMap1.TrackOverlay.TrackMode = TrackMode.Polygon; break; case "MULTILINE": winformsMap1.TrackOverlay.TrackMode = TrackMode.Line; break; default: winformsMap1.TrackOverlay.TrackMode = TrackMode.None; break; } } private void track_VertexAdding(object sender, VertexAddingTrackInteractiveOverlayEventArgs e) { SnapToLayerTrackInteractiveOverlay trackInteractiveOverlay = sender as SnapToLayerTrackInteractiveOverlay; PointShape closestPoint = null; switch (trackInteractiveOverlay.TrackMode) { case TrackMode.StraightLine: case TrackMode.Line: case TrackMode.Polygon: case TrackMode.Rectangle: closestPoint = FindNearestSnappingPoint(new PointShape(e.AddingVertex)); if (closestPoint == null) return; e.AddingVertex = new Vertex(closestPoint); break; } } private void track_TrackEnding(object sender, TrackEndingTrackInteractiveOverlayEventArgs e) { Debug.Print("TrackEnding"); SnapToLayerTrackInteractiveOverlay trackInteractiveOverlay = sender as SnapToLayerTrackInteractiveOverlay; PointShape closestPoint = null; switch (trackInteractiveOverlay.TrackMode) { case TrackMode.Point: PointShape currentPoint = new PointShape(e.TrackShape.GetWellKnownBinary()); closestPoint = FindNearestSnappingPoint(currentPoint); if (closestPoint == null) return; e.TrackShape = closestPoint; break; case TrackMode.StraightLine: LineShape straightLine = new LineShape(e.TrackShape.GetWellKnownBinary()); int straightLineVertexCount = straightLine.Vertices.Count() - 1; closestPoint = FindNearestSnappingPoint(new PointShape(straightLine.Vertices[straightLineVertexCount])); if (closestPoint == null) return; straightLine.Vertices[straightLineVertexCount] = new Vertex(closestPoint); e.TrackShape = straightLine; break; case TrackMode.Line: LineShape line = new LineShape(e.TrackShape.GetWellKnownBinary()); int lineVertexCount = line.Vertices.Count() - 1; closestPoint = FindNearestSnappingPoint(new PointShape(line.Vertices[lineVertexCount])); if (closestPoint == null) return; line.Vertices[lineVertexCount] = new Vertex(closestPoint); e.TrackShape = line; break; case TrackMode.Polygon: PolygonShape poly = new PolygonShape(e.TrackShape.GetWellKnownBinary()); int pointCount = poly.OuterRing.Vertices.Count() - 1; int indexForMovedVertex = poly.OuterRing.Vertices.Count - 2; if (poly.OuterRing.Vertices.Count == 4) { if (poly.OuterRing.Vertices[2] == poly.OuterRing.Vertices[3]) { indexForMovedVertex = 1; // Special for draw the 2nd vertex } } closestPoint = FindNearestSnappingPoint(new PointShape(poly.OuterRing.Vertices[indexForMovedVertex])); if (closestPoint == null) return; poly.OuterRing.Vertices[indexForMovedVertex] = new Vertex(closestPoint); e.TrackShape = poly; break; case TrackMode.Rectangle: closestPoint = FindNearestSnappingPoint(new PointShape(trackInteractiveOverlay.EndVertice)); if (closestPoint == null) return; double miniX = closestPoint.X < trackInteractiveOverlay.StartVertice.X ? closestPoint.X : trackInteractiveOverlay.StartVertice.X; double maxX = closestPoint.X > trackInteractiveOverlay.StartVertice.X ? closestPoint.X : trackInteractiveOverlay.StartVertice.X; double miniY = closestPoint.Y < trackInteractiveOverlay.StartVertice.Y ? closestPoint.Y : trackInteractiveOverlay.StartVertice.Y; double maxY = closestPoint.Y > trackInteractiveOverlay.StartVertice.Y ? closestPoint.Y : trackInteractiveOverlay.StartVertice.Y; RectangleShape newRectangleShape = new RectangleShape(miniX, maxY, maxX, miniY); e.TrackShape = newRectangleShape; break; default: break; } } private void track_TrackEnded(object sender, TrackEndedTrackInteractiveOverlayEventArgs e) { // Turn off the track mode winformsMap1.TrackOverlay.TrackMode = TrackMode.None; // First, find the center point of the created object Feature trackFeature = winformsMap1.TrackOverlay.TrackShapeLayer.InternalFeatures[0]; } private void track_TrackStarting(object sender, TrackStartingTrackInteractiveOverlayEventArgs e) { Debug.Print("TrackStarting"); PointShape closestPoint = FindNearestSnappingPoint(new PointShape(e.StartingVertex)); if (closestPoint == null) return; e.StartingVertex = new Vertex(closestPoint); } private PointShape FindNearestSnappingPoint(PointShape targetPointShape) { InMemoryFeatureLayer imfl = snapToLayerEditInteractiveOverlay.ToSnapInMemoryFeatureLayer; imfl.Open(); Collection<Feature> toSnapInMemoryFeatures = imfl.FeatureSource.GetFeaturesNearestTo(targetPointShape, GeographyUnit.Meter, 1, ReturningColumnsType.AllColumns); imfl.Close(); if (toSnapInMemoryFeatures.Count == 1) { BaseShape baseShape = toSnapInMemoryFeatures[0].GetShape(); string baseShapeType = baseShape.GetWellKnownType().ToString(); if (baseShapeType == "Multipoint") { MultipointShape multiPointShape = (MultipointShape)toSnapInMemoryFeatures[0].GetShape(); foreach (PointShape point in multiPointShape.Points) { PointShape toSnapPointShape = point; double Distance = toSnapPointShape.GetDistanceTo(targetPointShape, GeographyUnit.Meter, DistanceUnit.Meter); if (Distance <= tolerance) { return new PointShape(toSnapPointShape.X, toSnapPointShape.Y); } } } else if (baseShapeType == "Point") { PointShape toSnapPointShape = (PointShape)baseShape; double Distance = toSnapPointShape.GetDistanceTo(targetPointShape, GeographyUnit.Meter, DistanceUnit.Meter); if (Distance <= tolerance) { return new PointShape(toSnapPointShape.X, toSnapPointShape.Y); } } } return null; } private void btnPoint_Click(object sender, EventArgs e) { SwitchDrawingMode(sender); } private void btnLine_Click(object sender, EventArgs e) { SwitchDrawingMode(sender); } private void btnRectangle_Click(object sender, EventArgs e) { SwitchDrawingMode(sender); } private void btnMultiline_Click(object sender, EventArgs e) { SwitchDrawingMode(sender); } private void btnPolygon_Click(object sender, EventArgs e) { SwitchDrawingMode(sender); } }
using System.Collections.ObjectModel; using ThinkGeo.MapSuite.Core; using ThinkGeo.MapSuite.DesktopEdition; public enum ToleranceCoordinates { World, Screen }; public class SnapToLayerEditInteractiveOverlay : EditInteractiveOverlay { private PointStyle controlPointStyle; private PointStyle draggedControlPointStyle; private InMemoryFeatureLayer toSnapInMemoryFeatureLayer; private float tolerance; private DistanceUnit toleranceUnit; private GeographyUnit geographyUnit; private RectangleShape currentWorldExtent; private float mapWidth; private float mapHeight; private ToleranceCoordinates toleranceType; //Property for the non dragged control point style. public PointStyle ControlPointStyle { get { return controlPointStyle; } set { controlPointStyle = value; } } //Property for the dragged control point style. public PointStyle DraggedControlPointStyle { get { return draggedControlPointStyle; } set { draggedControlPointStyle = value; } } //InMemoryFeatureLayer for the layer to be snapped to. public InMemoryFeatureLayer ToSnapInMemoryFeatureLayer { get { return toSnapInMemoryFeatureLayer; } set { toSnapInMemoryFeatureLayer = value; } } public ToleranceCoordinates ToleranceType { get { return toleranceType; } set { toleranceType = value; } } public float Tolerance { get { return tolerance; } set { tolerance = value; } } public DistanceUnit ToleranceUnit { get { return toleranceUnit; } set { toleranceUnit = value; } } //Overrides the MoveVertexCore to have the logic to check if the dragged control point is within tolerance. protected override Feature MoveVertexCore(Feature sourceFeature, PointShape sourceControlPoint, PointShape targetControlPoint) { VertexMovingEditInteractiveOverlayEventArgs vertexMovingEditInteractiveOverlayEventArgs = new VertexMovingEditInteractiveOverlayEventArgs(false, sourceFeature, new Vertex(targetControlPoint)); PointShape snapPointShape = null; if (toleranceType == ToleranceCoordinates.Screen) { snapPointShape = FindNearestSnappingPointPixel(targetControlPoint); } else { snapPointShape = FindNearestSnappingPoint(targetControlPoint); } if (snapPointShape != null) { vertexMovingEditInteractiveOverlayEventArgs.MovingVertex = new Vertex(snapPointShape); } return base.MoveVertexCore(sourceFeature, sourceControlPoint, new PointShape(vertexMovingEditInteractiveOverlayEventArgs.MovingVertex)); } //Function to find if dragged control point is within the tolerance of a vertex of layer in screen (pixels) coordinates. private PointShape FindNearestSnappingPointPixel(PointShape targetPointShape) { toSnapInMemoryFeatureLayer.Open(); Collection<Feature> toSnapInMemoryFeatures = toSnapInMemoryFeatureLayer.FeatureSource.GetFeaturesNearestTo(targetPointShape, GeographyUnit.Meter, 1, ReturningColumnsType.AllColumns); toSnapInMemoryFeatureLayer.Close(); if (toSnapInMemoryFeatures.Count == 1) { MultipointShape multiPointShape = (MultipointShape)toSnapInMemoryFeatures[0].GetShape(); foreach (PointShape point in multiPointShape.Points) { PointShape toSnapPointShape = point; float screenDistance = ExtentHelper.GetScreenDistanceBetweenTwoWorldPoints(currentWorldExtent, toSnapPointShape, targetPointShape, mapWidth, mapHeight); if (screenDistance <= tolerance) { return new PointShape(toSnapPointShape.X, toSnapPointShape.Y); } } } return null; } //Function to find if dragged control point is within the tolerance of a vertex of layer in world coordinates. private PointShape FindNearestSnappingPoint(PointShape targetPointShape) { toSnapInMemoryFeatureLayer.Open(); Collection<Feature> toSnapInMemoryFeatures = toSnapInMemoryFeatureLayer.FeatureSource.GetFeaturesNearestTo(targetPointShape, GeographyUnit.Meter, 1, ReturningColumnsType.AllColumns); toSnapInMemoryFeatureLayer.Close(); if (toSnapInMemoryFeatures.Count == 1) { BaseShape baseShape = toSnapInMemoryFeatures[0].GetShape(); string baseShapeType = baseShape.GetWellKnownType().ToString(); if (baseShapeType == "Multipoint") { MultipointShape multiPointShape = (MultipointShape)toSnapInMemoryFeatures[0].GetShape(); foreach (PointShape point in multiPointShape.Points) { PointShape toSnapPointShape = point; double Distance = toSnapPointShape.GetDistanceTo(targetPointShape, geographyUnit, toleranceUnit); if (Distance <= tolerance) { return new PointShape(toSnapPointShape.X, toSnapPointShape.Y); } } } else if (baseShapeType == "Point") { PointShape toSnapPointShape = (PointShape)baseShape; double Distance = toSnapPointShape.GetDistanceTo(targetPointShape, geographyUnit, toleranceUnit); if (Distance <= tolerance) { return new PointShape(toSnapPointShape.X, toSnapPointShape.Y); } } } return null; } //Overrides the DrawCore function to draw the Edit Layers, the vertices and tolerance ellipses of layer to snap to, //and the control points. protected override void DrawCore(GeoCanvas canvas) { //Sets the geography Unit used in FindNearestSnappingPoint function geographyUnit = canvas.MapUnit; currentWorldExtent = canvas.CurrentWorldExtent; mapWidth = canvas.Width; mapHeight = canvas.Height; //Draws the Edit Shapes as default. Collection<SimpleCandidate> labelsInAllLayers = new Collection<SimpleCandidate>(); EditShapesLayer.Open(); EditShapesLayer.Draw(canvas, labelsInAllLayers); canvas.Flush(); //Draw the vertices and tolerance ellipses of layer to snap to. toSnapInMemoryFeatureLayer.Open(); Collection<Feature> toSnapPoints = toSnapInMemoryFeatureLayer.FeatureSource.GetAllFeatures(ReturningColumnsType.AllColumns); toSnapInMemoryFeatureLayer.Close(); foreach (Feature feature in toSnapPoints) { Collection<PointShape> allPoints = new Collection<PointShape>(); if (feature.GetWellKnownType() == WellKnownType.Multipoint) { MultipointShape multiPointShape = (MultipointShape)feature.GetShape(); allPoints = multiPointShape.Points; } else { PointShape multiPointShape = (PointShape)feature.GetShape(); allPoints.Add(multiPointShape); } //MultipointShape multiPointShape = (MultipointShape)feature.GetShape(); foreach (PointShape point in allPoints) { // Draws the vertex. PointShape pointShape = point; //canvas.DrawEllipse(pointShape, 5, 5, new GeoSolidBrush(GeoColor.StandardColors.Black), DrawingLevel.LevelOne); // Draws the tolerance ellipse. if (toleranceType == ToleranceCoordinates.Screen) { ScreenPointF screenPointF = ExtentHelper.ToScreenCoordinate(canvas.CurrentWorldExtent, pointShape, canvas.Width, canvas.Height); //canvas.DrawEllipse(screenPointF, tolerance * 2, tolerance * 2, new GeoPen(GeoColor.StandardColors.Black), new GeoSolidBrush(), DrawingLevel.LevelFour, 0, 0, PenBrushDrawingOrder.PenFirst); } else { EllipseShape ellipseShape = new EllipseShape(pointShape, tolerance, canvas.MapUnit, toleranceUnit); //canvas.DrawArea(ellipseShape, new GeoPen(GeoColor.StandardColors.Black), DrawingLevel.LevelOne); } } } //Draws the control points. ExistingControlPointsLayer.Open(); Collection<Feature> controlPoints = ExistingControlPointsLayer.FeatureSource.GetAllFeatures(ReturningColumnsType.AllColumns); //Loops thru the control points. foreach (Feature feature in controlPoints) { //Looks at the value of "state" to draw the control point as dragged or not. if (feature.ColumnValues["state"] != "selected") { Feature[] features = new Feature[1] { feature }; controlPointStyle.Draw(features, canvas, labelsInAllLayers, labelsInAllLayers); } else { Feature[] features = new Feature[1] { feature }; draggedControlPointStyle.Draw(features, canvas, labelsInAllLayers, labelsInAllLayers); } } //Draws the drag point and the rotate point DragControlPointsLayer.Open(); DragControlPointsLayer.Draw(canvas, labelsInAllLayers); RotateControlPointsLayer.Open(); RotateControlPointsLayer.Draw(canvas, labelsInAllLayers); canvas.Flush(); } protected override Feature DragFeatureCore(Feature sourceFeature, PointShape sourceControlPoint, PointShape targetControlPoint) { PointShape snapDragPoint = targetControlPoint; LineShape lineShape = sourceFeature.GetShape() as LineShape; if (lineShape != null) { double xOffset = targetControlPoint.X - sourceControlPoint.X; double yOffset = targetControlPoint.Y - sourceControlPoint.Y; PointShape snapPointShape = null; foreach (var item in lineShape.Vertices) { PointShape pointShape = new PointShape(item.X + xOffset, item.Y + yOffset); if (toleranceType == ToleranceCoordinates.Screen) { snapPointShape = FindNearestSnappingPointPixel(pointShape); } else { snapPointShape = FindNearestSnappingPoint(pointShape); } if (snapPointShape != null) { snapDragPoint = new PointShape(targetControlPoint.X + snapPointShape.X - pointShape.X, targetControlPoint.Y + snapPointShape.Y - pointShape.Y); break; } } } Feature feature = base.DragFeatureCore(sourceFeature, sourceControlPoint, snapDragPoint); CalculateAllControlPoints(); return feature; } }
using ThinkGeo.MapSuite.Core; using ThinkGeo.MapSuite.DesktopEdition; public class SnapToLayerTrackInteractiveOverlay : TrackInteractiveOverlay { private Vertex startVertice; public Vertex StartVertice { get { return startVertice; } set { startVertice = value; } } private Vertex endVertice; public Vertex EndVertice { get { return endVertice; } set { endVertice = value; } } public SnapToLayerTrackInteractiveOverlay() : base() { base.TrackEnding += RectangleTrackInteractiveOverlay_TrackEnding; } private void RectangleTrackInteractiveOverlay_TrackEnding(object sender, TrackEndingTrackInteractiveOverlayEventArgs e) { if (base.TrackMode == TrackMode.Rectangle && base.Vertices.Count == 2) { startVertice = base.Vertices[0]; endVertice = base.Vertices[1]; } } }