因项目需要,需要做一个旋转注记的工具。因为注记这玩意用的比较少,网上资源也很少,所以做起来相当头疼。在经过一番研究之后,终于搞清楚注记的存储原理了,原来是和Element的类似,只不过注记是要把Element写入FeatureClass的。那么好,事情简单多了,能实现旋转Element,就能实现旋转注记了。于是乎又在网上找旋转Element的资源,没想到又遇上难题。ArcEngine里面实现带轨迹的元素旋转的接口是IRotateTracker,但是这玩意很不好用,不知道是不是我没研究到位,我用了之后一点反应也没有,RotateTracker的Angle值始终为0,这可愁死人了,网上搜索发现好多网友也跟我同样的遭遇,这难道是BUG??且不管这些了,项目总是要进行的,我只能换别的方法了。
说到旋转其实倒是不难,ITransform2D.Rotate()方法还是很常用的,难就难在旋转的轨迹上。所幸Elment的操作还是很轻松的,只要在OnMouseMove里面时时进行旋转就行了,轨迹也很顺畅。而Annotation的操作就不那么轻松了,由于涉及到动态存储数据到空间数据库中,旋转轨迹相当不顺畅,出现卡滞现象,没有操作感可言。于是乎又挠头了,在挠掉了数以万计的头皮屑之后终于想到方法了。既然Elment操作很流畅,那为什么不用Elment做为轨迹呢,然后在OnMouseUp里面做最终的旋转?说干就干,我想的方法果然可行。但最核心的难题出现了,怎么在OnMouseMove里面动态获取Elment的角度呢,相信这也是很多网友想知道的问题,让大家听了这么多废话,那么直接上代码吧!

/// <summary>
/// 旋转元素工具
/// </summary>
public sealed class BTGraphicsRotateElement : BaseTool
{
#region 成员变量 private IHookHelper m_hookHelper = null;
private IPoint m_point;
private IElement m_element;
private bool m_moving;
private IPoint m_oldPoint;
private IElement m_viewElement;
/// <summary>
/// 获取或设置标注图层
/// </summary>
public IFeatureLayer AnnotationLayer { get; set; } #endregion #region 构造函数 public BTGraphicsRotateElement()
{
base.m_category = "";
base.m_caption = "";
base.m_message = "";
base.m_toolTip = "旋转元素";
base.m_name = "";
base.m_cursor = Cursors.Default;
try
{
base.m_bitmap = Properties.Resources.bmp_EditingRotate;
}
catch
{
base.m_bitmap = null;
}
}
public BTGraphicsRotateElement(IFeatureLayer annotationLayer)
: this()
{
AnnotationLayer = annotationLayer;
}
#endregion #region 方法覆写 public override void OnCreate(object hook)
{
try
{
m_hookHelper = new HookHelperClass();
m_hookHelper.Hook = hook;
if (m_hookHelper.ActiveView == null)
{
m_hookHelper = null;
}
}
catch
{
m_hookHelper = null;
} if (m_hookHelper == null)
base.m_enabled = false;
else
base.m_enabled = true; // TODO: Add other initialization code } public override void OnClick()
{
// TODO: Add StationTool.OnClick implementation
} public override void OnMouseDown(int Button, int Shift, int X, int Y)
{
if (Button == )
{
IGraphicsContainer pGraphicsContainer = m_hookHelper.ActiveView as IGraphicsContainer;
m_point = m_hookHelper.ActiveView.ScreenDisplay.DisplayTransformation.ToMapPoint(X, Y);
IEnumElement pEnumElement = pGraphicsContainer.LocateElements(m_point, );
if (pEnumElement == null) return;
m_element = pEnumElement.Next(); if (m_element is AnnotationElement)
{
if (AnnotationLayer == null)
{
ILayer pLayer = Utility.GetFeatureLayer("注记", m_hookHelper);
AnnotationLayer = pLayer as IFeatureLayer;
}
if (AnnotationLayer == null)
{
MessageBox.Show("未找到注记图层!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
// 根据注记的参考坐标调整字体显示大小【修正部分】
IAnnotationClassExtension pAnnotationClassExtension = AnnotationLayer.FeatureClass.Extension as IAnnotationClassExtension;
ITextSymbol pSymbol = ((ITextElement)m_element).Symbol;
pSymbol.Size = pSymbol.Size / (m_hookHelper.ActiveView.FocusMap.MapScale / pAnnotationClassExtension.ReferenceScale);
ITextElement pTextElement = new TextElementClass { Text = ((ITextElement)m_element).Text, Symbol = pSymbol }; m_viewElement = pTextElement as IElement;
m_viewElement.Geometry = m_element.Geometry;
m_hookHelper.ActiveView.GraphicsContainer.AddElement(m_viewElement, );
m_hookHelper.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, m_viewElement, null);
} // 移动状态信息
m_moving = true; }
} public override void OnMouseMove(int Button, int Shift, int X, int Y)
{
if (Button == )
{
if (!m_moving) return; IPoint centerPoint = new PointClass
{
X = (m_element.Geometry.Envelope.LowerLeft.X + m_element.Geometry.Envelope.LowerRight.X) / ,
Y = (m_element.Geometry.Envelope.LowerLeft.Y + m_element.Geometry.Envelope.UpperRight.Y) /
};
if (m_element is AnnotationElement)
{
// 如果旧点为空,则赋OnMouseDown事件所获取的点值
if (m_oldPoint == null)
m_oldPoint = m_point;
// 新点为当前的鼠标点坐标
IPoint newPoint = m_hookHelper.ActiveView.ScreenDisplay.DisplayTransformation.ToMapPoint(X, Y);
// 获取旧点角度
IPointCollection pPointCollection = new PolylineClass();
object missing = Type.Missing;
pPointCollection.AddPoint(centerPoint, ref missing, ref missing);
pPointCollection.AddPoint(m_oldPoint, ref missing, ref missing);
double oldAngle = GetAngle(pPointCollection as IPolyline);
// 获取新点角度
IPointCollection pointCollection = new PolylineClass();
pointCollection.AddPoint(centerPoint, ref missing, ref missing);
pointCollection.AddPoint(newPoint, ref missing, ref missing);
double newAngle = GetAngle(pointCollection as IPolyline);
// 旋转Element,角度为新旧点之差
ITransform2D pTransform2D = m_viewElement as ITransform2D;
pTransform2D.Rotate(centerPoint, (newAngle - oldAngle));
m_hookHelper.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, m_viewElement, m_hookHelper.ActiveView.Extent); // 更新旧点变量
m_oldPoint = newPoint; }
else
{
object missing = Type.Missing;
IPoint newPoint = m_hookHelper.ActiveView.ScreenDisplay.DisplayTransformation.ToMapPoint(X, Y);
IPointCollection pPointCollection = new PolylineClass();
pPointCollection.AddPoint(centerPoint, ref missing, ref missing);
pPointCollection.AddPoint(m_point, ref missing, ref missing);
double oldAngle = GetAngle(pPointCollection as IPolyline); IPointCollection pointCollection = new PolylineClass();
pointCollection.AddPoint(centerPoint, ref missing, ref missing);
pointCollection.AddPoint(newPoint, ref missing, ref missing);
double newAngle = GetAngle(pointCollection as IPolyline); ITransform2D pTransform2D = m_element as ITransform2D;
pTransform2D.Rotate(centerPoint, (newAngle - oldAngle));
m_hookHelper.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, m_element, m_hookHelper.ActiveView.Extent);
m_point = newPoint;
} }
} public override void OnMouseUp(int Button, int Shift, int X, int Y)
{
if (Button == )
{
if (m_element is AnnotationElement)
{
IPoint centerPoint = new PointClass
{
X = (m_element.Geometry.Envelope.LowerLeft.X + m_element.Geometry.Envelope.LowerRight.X) / ,
Y = (m_element.Geometry.Envelope.LowerLeft.Y + m_element.Geometry.Envelope.UpperRight.Y) /
};
if (AnnotationLayer == null)
{
ILayer pLayer = Utility.GetFeatureLayer("注记", m_hookHelper);
AnnotationLayer = pLayer as IFeatureLayer;
}
if (AnnotationLayer == null)
{
MessageBox.Show("未找到注记图层!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
IFeatureClass pFeatureClass = AnnotationLayer.FeatureClass;
IDataset pDataset = (IDataset)pFeatureClass;
IWorkspaceEdit pWorkspaceEdit = (IWorkspaceEdit)pDataset.Workspace;
pWorkspaceEdit.StartEditing(true);
pWorkspaceEdit.StartEditOperation();
pWorkspaceEdit.EnableUndoRedo(); double angle = ((ITextElement)m_viewElement).Symbol.Angle;
double oldAngle = ((ITextElement)m_element).Symbol.Angle;
ITransform2D pTransform2D = m_element as ITransform2D;
pTransform2D.Rotate(centerPoint, (angle - oldAngle) * Math.PI / ); IGraphicsContainer pGraphicsContainer = m_hookHelper.ActiveView as IGraphicsContainer;
pGraphicsContainer.UpdateElement(m_element);
pWorkspaceEdit.DisableUndoRedo();
pWorkspaceEdit.StopEditOperation();
pWorkspaceEdit.StopEditing(true);
pGraphicsContainer.DeleteElement(m_viewElement);
m_hookHelper.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography, null, m_hookHelper.ActiveView.Extent);
m_hookHelper.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, m_hookHelper.ActiveView.Extent);
}
m_moving = false;
m_element = null;
m_point = null;
m_viewElement = null;
m_oldPoint = null;
}
} #endregion #region 方法函数 /// <summary>
/// 获取线的角度(弧度)
/// </summary>
/// <param name="pPolyline">线</param>
/// <returns></returns>
private static double GetAngle(IPolyline pPolyline)
{
ILine pTangentLine = new Line();
pPolyline.QueryTangent(esriSegmentExtension.esriNoExtension, 0.5, true, pPolyline.Length, pTangentLine);
Double radian = pTangentLine.Angle; /*
Double angle = radian * 180 / Math.PI;
// 如果要设置正角度执行以下方法
while (angle < 0)
{
angle = angle + 360;
}
// 返回角度
return angle;
*/ // 返回弧度
return radian;
} #endregion
}

以上代码是做成BaseTool类,可以直接放到项目中使用,唯一要注意的是,里面涉及到注记的图层需要指定,如果不指定的话可能会报错,我是用的我项目里面的注记图层来做的,如果单纯操作Elment可以不考虑。后面还附了一个获取角度的方法,准确的来说是获取弧度,因为ITransform2D.Rotate()里面的Angle是弧度。
/*****分割线*****/
以上工具在项目中可以正常使用,唯一不足的是用作旋转时临时显示的元素大小在不同比例尺下跟注记本身的大小会有差异,因此第二个版本我已经做了改进,原理就是利用比例尺的差异修正元素大小,测试通过,见【修正部分】。

【ArcEngine入门与提高】Element(元素)、Annotation(注记)旋转的更多相关文章

  1. ArcGis 创建Annotation注记要素类、添加注记要素 并加载到Activeview AO C#

    AO中一般有两种方式存储图面注记元素,一种使用TextElement,它是文档级的元素,编辑后要通过文档(mxd)保存:另一种是使用Annotation要素类,它是一个独立的要素类(featurecl ...

  2. 【ESRI论坛6周年征文】ArcEngine注记(Anno/ Label/Element等)处理专题 -入门篇

    原发表于ESRI中国社区,转过来.我的社区帐号:jhlong http://bbs.esrichina-bj.cn/ESRI/viewthread.php?tid=122097 ----------- ...

  3. XSD标准架构-----<xsd:element> 元素详解

    声明一个元素.     <element abstract = Boolean : false block = (#all | List of (extension | restriction ...

  4. webdriver实用指南迁移至gitbbok并改名为selenium webdriver从入门到提高

    背景 几年前我写了一本关于selenium webdriver的小册子,主要讲了一些selenium在进行测试过程中会遇到的场景以及解决方案,陆陆续续在github上收到了100+的star,在这里我 ...

  5. SignalR 2.0 入门与提高

    SignalR 2.0 入门与提高 SignalR 2.0 最近整理了SignalR2.0 部分知识点,原文翻译,由于自己是土鳖,翻译得不好的地方,欢迎指正!仅供各位初学者学习! 第一节. 入门ASP ...

  6. 【转载】【时序约束学习笔记1】Vivado入门与提高--第12讲 时序分析中的基本概念和术语

    时序分析中的基本概念和术语 Basic concept and Terminology of Timing Analysis 原文标题及网址: [时序约束学习笔记1]Vivado入门与提高--第12讲 ...

  7. Android 开发 音视频从入门到提高 任务列表 转载

    <Android 音视频从入门到提高 —— 任务列表> 1. 在 Android 平台绘制一张图片,使用至少 3 种不同的 API,ImageView,SurfaceView,自定义 Vi ...

  8. 包建强的培训课程(16):Android新技术入门和提高

    @import url(/css/cuteeditor.css); Normal 0 10 pt 0 2 false false false EN-US ZH-CN X-NONE $([{£¥·‘“〈 ...

  9. 关东升的iOS实战系列图书 《iOS实战:入门与提高卷(Swift版)》已经上市

             承蒙广大读者的厚爱我的 <iOS实战:入门与提高卷(Swift版)>京东上市了,欢迎广大读者提出宝贵意见.http://item.jd.com/11766718.html ...

随机推荐

  1. 基于.net mvc的校友录(七、文件上传以及多对多关系表的LINQ查询实现)

    图片的上传与调用 图片的上传就是文件的上传,在前台使用的是type="file"的input,但是,要将表单声明为multipart/form-data模式,方法是在BeginFo ...

  2. 阴影 box-shadow(二)

    阴影 box-shadow(二) 1.阴影模糊半径与阴影扩展半径的区别 阴影模糊半径:此参数可选,其值只能是为正值,如果其值为0时,表示阴影不具有模糊效果,其值越大阴影的边缘就越模糊: 阴影扩展半径: ...

  3. Excel下用SQL语句实现AVEDEV函数功能

    Excel下AVEDEV函数返回一组数据点到其算术平均值的绝对偏差的平均值. AVEDEV 是对一组数据中变化性的度量.最常见的应用就是统计平均分差. 但是如果在Excel中写SQL进行一些复杂的统计 ...

  4. 【Subsets II】cpp

    题目: Given a collection of integers that might contain duplicates, nums, return all possible subsets. ...

  5. Window.document对象(2)

    四.操作样式 首先利用元素的ID找到该元素,存于一个变量中: var a = document.getElementById("id"): 然后可以对该元素的属性进行操作: a.s ...

  6. ZeroMQ 在 centos 6.5_x86_64 下的安装

    ZeroMQ 在 centos 6.5_x86_64 下的安装 作者:chszs,转载需注明.博客主页:http://blog.csdn.net/chszs 一.ZeroMQ介绍 ZeroMQ是一个开 ...

  7. 浅谈IT

    在没有学计算机应用技术之前我对IT的认知度几乎为零,曾经还天真的认为IT就是白领,只要做上IT行业,以后便可高枕无忧.后来阴差阳错学了这个专业.通过一年的学习,虽然学艺不精但多少对IT行业了解的一知半 ...

  8. Codeforces Round #249 (Div. 2) D. Special Grid 枚举

    题目链接: http://codeforces.com/contest/435/problem/D D. Special Grid time limit per test:4 secondsmemor ...

  9. BZOJ3874 codevs3361 宅男计划

    AC通道1:http://www.lydsy.com/JudgeOnline/problem.php?id=3874 AC通道2:http://codevs.cn/problem/3361/ [题目分 ...

  10. 【bzoj1006】[HNOI2008]神奇的国度

    1006: [HNOI2008]神奇的国度 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 3114  Solved: 1401[Submit][Sta ...