ArcMobile的CoordinateCollection在逆时针添加点时自动调整节点顺序的问题

  为了使用ArcMobile实现量测功能,LZ自定义了一个MapGraphicLayer用于绘图,代码如下:

using System.Drawing;
using ESRI.ArcGIS.Mobile;
using ESRI.ArcGIS.Mobile.Geometries;

namespace LandInspections
{
    public class MeasureLayer : MapGraphicLayer
    {
        /// Defines a symbol class instance for displaying point
        private Symbol drawSymbol;

        /// Defines a CoordinateCollection instance to store custom features
        private CoordinateCollection coordinateCollection = new CoordinateCollection();

        /// Get or set coordinate collection stored in custom graphic layer 
        public CoordinateCollection Coordinates
        {
            get
            {
                return coordinateCollection;
            }
            set
            {
                coordinateCollection = value;
            }
        }

        /// Initializes a new instance of custom graphic layer
        public MeasureLayer()
            : base("MeasureLayer")
        {
            drawSymbol = new Symbol(
                new PointPaintOperation(
                    Color.Green, 3, 0, Color.LightGreen, 100, 25, PointPaintStyle.Circle));
        }

        /// Draw method being called after adding to map
        protected override void Draw(Display display)
        {
            //return if display is null
            if (display == null)
                return;
            //return if drawing is cancelled
            if (display.DrawingCanceled)
                return;
            drawSymbol.DrawArea(display, coordinateCollection);
        }

        protected override void Dispose(bool disposing)
        {
            //Dispose symbol implementing IDisposible
            try
            {
                if (disposing)
                {
                    if (drawSymbol != null)
                        drawSymbol.Dispose();
                    drawSymbol = null;

                    coordinateCollection = null;
                }
            }
            finally
            {
                base.Dispose(disposing);
            }
        }
    }
}

  在“量测”按钮所在的窗体代码中,添加如下代码:

/// <summary>
/// MapGraphicLayer的坐标点
/// </summary>
private CoordinateCollection coords = new CoordinateCollection();

private BtnMeasure_Click(object sender, EventArgs e)
{
    if (this.txtMeasure.Visible)//txtMeasure是用来显示量测结果的控件
    {
        this.txtMeasure.Visible = false;
        this.coords.Clear();
        this.map1.MapGraphicLayers.Remove(this.measureLayer);
        this._mapAction = MyMapAction.None;
    }
    else
    {
        this.txtMeasure.Text = "量测:
长度:0.000 米
面积:0.000 平方米";
        this.measureLayer = new MeasureLayer();
        this.measureLayer.Coordinates = this.coords;
        this.map1.MapGraphicLayers.Add(this.measureLayer);
        this._mapAction == MyMapAction.Measure;
        this.txtMeasure.Visible = true;
    }
}

private void map1_MouseUp(object sender, MapMouseEventArgs e)
{
    if (this._mapAction == MyMapAction.Measure)
    {
        Coordinate coord = this.map1.ToMap(e.X, e.Y);
        this.coords.Add(coord);
        Polyline line = new Polyline(this.measureLayer.Coordinates);
        Polygon area = new Polygon(this.measureLayer.Coordinates);
        this.txtMeasure.Text = String.Format("量测:
长度:{0} 米
面积:{1} 平方米",
            line.GetLength().ToString("f3"), area.GetArea().ToString("f3"));
        this.map1.Refresh();
    }
}

  运行后,发现顺时针点击屏幕的绘图结果正确,但是逆时针点击屏幕时绘图结果错误。

  检查后发现是因为ESRI.ArcGIS.Mobile.Geometries.CoordinateCollection类的Add方法对点集的顺序进行了自动调整,在this.coords.Add(coord)时点集的顺序已经被改变了。

  添加点1:CoordinateCollection中点集为[1]。

  添加点2:CoordinateCollection中点集为[1,2,1]。

  添加点3:CoordinateCollection中点集为[1,3,2,1]。

  添加点4:CoordinateCollection中点击为[1,4,2,3,1]。

  为解决这一问题,LZ在程序中定义一个List<Coordinate> coords,用来存储正确顺序的点集,在自定义的MapGraphicLayer中添加一个SetCoordinate方法,用来保证以顺时针方向添加节点到CoordinateCollection中。代码如下:

public void SetCoordinate(System.Collections.Generic.List<Coordinate> coords)
{
    if (coords == null || coords.Count < 1)
        return;
    if (this.coordinateCollection == null)
        this.coordinateCollection = new CoordinateCollection();
  this.coordinateCollection.Clear();
//若为顺时针,则直接赋值 for (int i = 0; i < coords.Count; i++) { this.coordinateCollection.Add(new Coordinate(coords[i].X, coords[i].Y)); if (this.coordinateCollection.IsCounterClockwise == true) break; } //若为逆时针,则反向以顺时针方式将点集添加到CoordinateCollection中 if (this.coordinateCollection.IsCounterClockwise == true) { this.coordinateCollection.Clear(); this.coordinateCollection.Add(new Coordinate(coords[0].X, coords[0].Y)); for (int i = coords.Count - 1; i > 0; i--) { this.coordinateCollection.Add(new Coordinate(coords[i].X, coords[i].Y)); } } }

  相应的,“量测”功能所在窗体的代码也需要进行相应的修改,代码如下:

/// <summary>
/// MapGraphicLayer的坐标点
/// </summary>
private List<Coordinate> coords = new List<Coordinate>();

private BtnMeasure_Click(object sender, EventArgs e)
{
    if (this.txtMeasure.Visible)//txtMeasure是用来显示量测结果的控件
    {
        this.txtMeasure.Visible = false;
        this.coords.Clear();
        this.map1.MapGraphicLayers.Remove(this.measureLayer);
        this._mapAction = MyMapAction.None;
    }
    else
    {
        this.txtMeasure.Text = "量测:
长度:0.000 米
面积:0.000 平方米";
        this.measureLayer = new MeasureLayer();
        this.measureLayer.Coordinates.Clear();
this.map1.MapGraphicLayers.Add(this.measureLayer); this._mapAction == MyMapAction.Measure; this.txtMeasure.Visible = true; } } private void map1_MouseUp(object sender, MapMouseEventArgs e) { if (this._mapAction == MyMapAction.Measure) { Coordinate coord = this.map1.ToMap(e.X, e.Y); this.coords.Add(coord);
this.measureLayer.SetCoordinate(this.coords); Polyline line
= new Polyline(this.measureLayer.Coordinates); Polygon area = new Polygon(this.measureLayer.Coordinates); this.txtMeasure.Text = String.Format("量测: 长度:{0} 米 面积:{1} 平方米", line.GetLength().ToString("f3"), area.GetArea().ToString("f3")); this.map1.Refresh(); } }

  经过测试,这种方式是可行的。之后大概是因为无聊,也可能是为了验证自己的想法,又分别测试了完全反向插入节点和完全正向插入节点的情况,结果出乎意料,竟然都是正确的???

  完全反向插入节点:即将[1,2,3,4]以[1,4,3,2]的顺序插入,无论节点顺序是顺时针还是逆时针。测试代码如下:

public void SetCoordinate(System.Collections.Generic.List<Coordinate> coords)
{
   if (coords == null || coords.Count < 1)
       return;
   if (this.coordinateCollection == null)
       this.coordinateCollection = new CoordinateCollection();
this.coordinateCollection.Clear(); //反向插入节点 this.coordinateCollection.Add(new Coordinate(coords[0].X, coords[0].Y)); for (int i = coords.Count - 1; i > 0; i--) { this.coordinateCollection.Add(new Coordinate(coords[i].X, coords[i].Y)); } }

  完全正向插入节点:即将[1,2,3,4]以[1,2,3,4]的顺序插入,无论节点顺序是顺时针还是逆时针。测试代码如下:

public void SetCoordinate(System.Collections.Generic.List<Coordinate> coords)
{
    if (coords == null || coords.Count < 1)
        return;
    if (this.coordinateCollection == null)
        this.coordinateCollection = new CoordinateCollection();
    this.coordinateCollection.Clear();
    for (int i = 0; i < coords.Count; i++)
    {
        this.coordinateCollection.Add(new Coordinate(coords[i].X, coords[i].Y));
    }
}

  最后的事实证明,只要每次绘图时,将所有的节点重新添加一次即可,于是LZ最终选择了完全正向插入节点的方式。

原文地址:https://www.cnblogs.com/hibernation/p/3314269.html