【ArcEngine入门与提高】Element(元素)、Annotation(注记)旋转
因项目需要,需要做一个旋转注记的工具。因为注记这玩意用的比较少,网上资源也很少,所以做起来相当头疼。在经过一番研究之后,终于搞清楚注记的存储原理了,原来是和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(注记)旋转的更多相关文章
- ArcGis 创建Annotation注记要素类、添加注记要素 并加载到Activeview AO C#
AO中一般有两种方式存储图面注记元素,一种使用TextElement,它是文档级的元素,编辑后要通过文档(mxd)保存:另一种是使用Annotation要素类,它是一个独立的要素类(featurecl ...
- 【ESRI论坛6周年征文】ArcEngine注记(Anno/ Label/Element等)处理专题 -入门篇
原发表于ESRI中国社区,转过来.我的社区帐号:jhlong http://bbs.esrichina-bj.cn/ESRI/viewthread.php?tid=122097 ----------- ...
- XSD标准架构-----<xsd:element> 元素详解
声明一个元素. <element abstract = Boolean : false block = (#all | List of (extension | restriction ...
- webdriver实用指南迁移至gitbbok并改名为selenium webdriver从入门到提高
背景 几年前我写了一本关于selenium webdriver的小册子,主要讲了一些selenium在进行测试过程中会遇到的场景以及解决方案,陆陆续续在github上收到了100+的star,在这里我 ...
- SignalR 2.0 入门与提高
SignalR 2.0 入门与提高 SignalR 2.0 最近整理了SignalR2.0 部分知识点,原文翻译,由于自己是土鳖,翻译得不好的地方,欢迎指正!仅供各位初学者学习! 第一节. 入门ASP ...
- 【转载】【时序约束学习笔记1】Vivado入门与提高--第12讲 时序分析中的基本概念和术语
时序分析中的基本概念和术语 Basic concept and Terminology of Timing Analysis 原文标题及网址: [时序约束学习笔记1]Vivado入门与提高--第12讲 ...
- Android 开发 音视频从入门到提高 任务列表 转载
<Android 音视频从入门到提高 —— 任务列表> 1. 在 Android 平台绘制一张图片,使用至少 3 种不同的 API,ImageView,SurfaceView,自定义 Vi ...
- 包建强的培训课程(16):Android新技术入门和提高
@import url(/css/cuteeditor.css); Normal 0 10 pt 0 2 false false false EN-US ZH-CN X-NONE $([{£¥·‘“〈 ...
- 关东升的iOS实战系列图书 《iOS实战:入门与提高卷(Swift版)》已经上市
承蒙广大读者的厚爱我的 <iOS实战:入门与提高卷(Swift版)>京东上市了,欢迎广大读者提出宝贵意见.http://item.jd.com/11766718.html ...
随机推荐
- Daily Scrum3
今天我们小组开会内容分为以下部分: part 1: 汇报之前分配的任务进度: part 2:分配明天的任务. ◆Part 1 组员进度报告 彭佟小组完成的优化目标: 关于软件防滥用及垃圾信息拦 ...
- (转)-编写第一个ROS(创建工作空间workspace和功能包package)
原文网址:http://www.cnblogs.com/liuamin/p/5704281.html 刚接触ROS,学着写了第一个程序,怕以后忘记,就将其步骤记录下来.. 首先你必须保证你电脑已安装配 ...
- Careercup - Microsoft面试题 - 5175246478901248
2014-05-11 23:52 题目链接 原题: design an alarm clock for a deaf person. 题目:为聋人设计闹钟? 解法:聋人听不见,那么闪光.震动都可行.睡 ...
- MySQL数据库远程连接开启方法
有时候需要远程连接mysql数据库,默认是不可以的,可以参考下面的方法,解决下. 1.登陆自己机器的MySQL数据库:mysql -uroot -p密码 设置root用户可以任意IP访问,代码如下(可 ...
- JavaWeb实现文件上传下载功能实例解析
转:http://www.cnblogs.com/xdp-gacl/p/4200090.html JavaWeb实现文件上传下载功能实例解析 在Web应用系统开发中,文件上传和下载功能是非常常用的功能 ...
- IOS 打包后安装崩溃,debug正常运行
今天遇到个奇葩问题,archive后的包安装后有一个crash,必崩的.但是调试跟踪时是好的. 为了方便调试,使用了release模式,这样不用每次都archive后安装进行测试.由于没法运行时deb ...
- 802.11 wireless 二
802.11 wireless 2wireless spectrum(无线频谱)1.无线网络使用RF(射频)信号2.无线电也是电磁波3.频谱基于波长被划分,归为多个类型4.无线网络被归为微波段(mic ...
- JS 学习笔记--11---内置对象(Global/Math)
练习中使用的浏览器是IE10,如果各位朋友有不同意见或者遇到浏览器不兼容问题,希望指正 1.内置对象的定义:有ECMAScript实现提供的.不依赖与宿主环境的对象,在ECMAScript运行之前就已 ...
- 机器学习&&数据挖掘之一:决策树基础认识
决策树入门篇 前言:分类是数据挖掘中的主要分析手段,其任务就是对数据集进行学习并构造一个拥有预测功能的分类模型,用于预测未知样本的类标号,把类标号未知的样本按照某一规则映射到预先给定的类标号中. 分类 ...
- 【BZOJ】【2661】【Beijing WC2012】连连看
网络流/费用流/二分图最大权匹配 拆点费用流求最大权匹配……为什么我拿zyf和Hzwer的代码也交不过去……WA了那么多次……so sad 求路过的神牛指导啊>_<万分感谢 //BZOJ ...