【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 ...
随机推荐
- OC中数组类NSArray的详解,数组的遍历(二)
数组类的便利 1.for循环(大家都会的...) 2.NSEmunerator 3.for in 首先重点说下 第二种NSEmunerator枚举器,系统声明是 @interface NSEnumer ...
- c++ _beginthread
c++多线程编程 #include <windows.h> #include <process.h> /* _beginthread, _endthread */ #inclu ...
- Daily Scrum3
今天我们小组开会内容分为以下部分: part 1: 汇报之前分配的任务进度: part 2:分配明天的任务. ◆Part 1 组员进度报告 彭佟小组完成的优化目标: 关于软件防滥用及垃圾信息拦 ...
- 关于四则运算的代码debug测试
1.首先检测题目是否能为负数,0? 截图: 总结:如图所示出题数目为0的时候,并没提示重新输入,而是输出空白,而当输出题目为负数的时候系统提示错误,并且提示终止 2.检测操作值得范围: 总结:当操 ...
- 3、颜色的字符串、十进制、十六进制相互转换(color convert between dec、hex and string )
int color_int=***; 1.(十进制整数)转换成(十六进制的字符串) String color_hex = String.format("#%06X", (0xFFF ...
- Matlab交集并集的实现
>> a = [1 2 3 4 8 9]; >> b = [4 5 6 1] b = 4 5 6 1 >> c = intersect(a,b) c = 1 4 判 ...
- 引擎设计跟踪(九.14.2a) 导出插件问题修复和 Tangent Space 裂缝修复
由于工作很忙, 近半年的业余时间没空搞了, 不过工作马上忙完了, 趁十一有时间修了一些小问题. 这次更新跟骨骼动画无关, 修复了一个之前的, 关于tangent space裂缝的问题: 引擎设计跟踪( ...
- UML部署图(转载)
概述: 部署图用于可视化的软件组件部署的系统中的物理组件的拓扑结构. 因此,部署图是用来描述一个系统的静态部署视图.部署图由节点和它们之间的关系. 目的: 部署名称本身描述的原理图的目的.部署图用于描 ...
- org.eclipse.wst.common.project.facet.core.xml文件模板,解决eclipse编译报错。
<?xml version="1.0" encoding="UTF-8"?> <faceted-project> <fixed f ...
- 一套名企WEB前端面试题,不提供答案
1.说说你对Doctype的理解 2.web产品开发的流程 3.说说你对盒子模型的理解 4.前端页面有哪三层构成,分别是什么?作用是什么? 5.行内元素有哪些?块级元素有哪些?他们如何相互转化? 6. ...