因项目需要,需要做一个旋转注记的工具。因为注记这玩意用的比较少,网上资源也很少,所以做起来相当头疼。在经过一番研究之后,终于搞清楚注记的存储原理了,原来是和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. P3382: [Usaco2004 Open]Cave Cows 3 洞穴里的牛之三

    首先,我们先确定,最长的曼哈顿距离只可能为 x1+y2-(x2+y2) 和 x1-y1-(x2-y2) 所以我们只需要维护四个值, 分别代表 max(x+y) ; max(x-y) ; min(x+y ...

  2. Convert Sorted Array to Binary Search Tree

    Convert Sorted Array to Binary Search Tree Given an array where elements are sorted in ascending ord ...

  3. linux下搭建mysql主从

    在master上创建repl账户,用于复制. grant replication slave on *.* to 'repl'@'%' identified by 'P@$$W0rd'; flush ...

  4. 盘点Windows 8.1中隐藏着的25个秘密功能

    Windows 8.1正式版问世,带来了众多大家早已耳熟能详的“开始按钮”.“分屏显示”等功能.事实上,Windows 8.1贴心的设计细节有很多,多数细节隐藏于系统中某个不起眼的角落,科技网站PC ...

  5. UVALive - 6529 找规律+dp

    题目链接: http://acm.hust.edu.cn/vjudge/problem/47664 Eleven Time Limit: 5000MS 问题描述 In this problem, we ...

  6. BZOJ 4443: [Scoi2015]小凸玩矩阵 二分图最大匹配+二分

    题目链接: http://www.lydsy.com/JudgeOnline/problem.php?id=4443 题解: 二分答案,判断最大匹配是否>=n-k+1: #include< ...

  7. Vim 常用命令 一

    今天第一次学习了 Vim编辑器的一些使用  拿出来和大家分享下. 1.首先 列出 常用快捷键 u 表示 撤销上一步 x 表示 删除光标位内容 dd 表示 删除光标所在行内容 >G   表示 光标 ...

  8. 【Ural】【1519】Formula 1

    插头DP 本题为CDQ<基于连通性状态压缩的动态规划的……(我忘了)>里的例题!(嗯就是这样……) 先膜拜一下ccy大神……http://blog.sina.com.cn/s/blog_5 ...

  9. MyEclipse提示键配置、提示快捷键、提示背景色、关键字颜色、代码显示、编...

    1.提示键配置 一般默认情况下,Eclipse ,MyEclipse 的代码提示功能是比Microsoft Visual Studio的差很多的,主要是Eclipse ,MyEclipse本身有很多选 ...

  10. FullPage.js全屏滚动插件学习总结

    如今我们经常能见到全屏网站,尤其是国外网站.这些网站用几幅很大的图片或色块做背景,再添加一些简单的内容,显得格外的高端大气上档次.比如 iPhone 5C 的介绍页面(查看),QQ浏览器的官网站.如果 ...