目录
1.Content
<1>矢量与栅格的分级渲染
(1)矢量分级设色(对应ArcGIS中的 矢量图层右键->Symbology->Quantities->Graduated colors)
(2)栅格色带渲染(对应ArcGIS中的 栅格图层右键->Symbology->Stretched)
<2>要素选择与查找
(1)要素查找
(2)要素选择
<3>元素的文本标注和符号标注
(1)文本标注
(2)符号标注
2.Environment
3.Conclusion
分享几个近期遇到的问题,直接切入主题:
用色带(ColorRamp)对矢量数据进行分级设色,在ArcMap中点两下就能实现的功能,在Engine中实现起来稍微麻烦一点,网上看了不少的示例代码,都是用单一颜色或者自定义颜色进行的简单分级设色,不能满足业务需求,所以自己实现了一下用色带来进行渲染,效果如下
同时,参照CSDN里一个博主的栅格数据色带选择器方法,又实现了一下矢量的。
矢量色带分级设色代码:
///
/// 字段数据统计
///
/// 图层
/// 统计字段
/// 返回统计数据
public static Dictionary FieldDataStatistics(IFeatureLayer pFeatureLayer, string field)
{
Dictionary dict_DataInfo = new Dictionary();
IFeatureClass pFeatureClass = pFeatureLayer.FeatureClass;
IField pField = pFeatureClass.Fields.get_Field(pFeatureClass.Fields.FindField(field));
ICursor pCursor = pFeatureClass.Search(null, false) as ICursor;
IDataStatistics pDataStatistics = new DataStatisticsClass();
pDataStatistics.Field = field;
pDataStatistics.Cursor = pCursor;
IStatisticsResults pStatisticsResults = pDataStatistics.Statistics;
dict_DataInfo["Max"] = pStatisticsResults.Maximum;
dict_DataInfo["Min"] = pStatisticsResults.Minimum;
dict_DataInfo["Mean"] = pStatisticsResults.Mean;
dict_DataInfo["Sum"] = pStatisticsResults.Sum;
dict_DataInfo["Count"] = pStatisticsResults.Count;
dict_DataInfo["StandardDeviation"] = pStatisticsResults.StandardDeviation;
return dict_DataInfo;
}
///
/// 矢量分级符号化渲染(手动分级)
///
/// 图层
/// 字段
/// 分级数
/// 色带对象
/// 是否反转
public static void GraduatedColorsRender(ILayer pLayer, string field, int breakCount, IColorRamp pColorRampD, bool isInvert)
{
// 统计数据
Dictionary dict_StasDataInfo = FieldDataStatistics(pLayer as IFeatureLayer, field);
double maxBreak = Convert.ToDouble(dict_StasDataInfo["Max"]);
double minBreak = Convert.ToDouble(dict_StasDataInfo["Min"]);
IGeoFeatureLayer pGeoFeatureLayer = pLayer as IGeoFeatureLayer;
// 创建断点分级渲染器,并设置属性
IClassBreaksRenderer pClassBreaksRenderer = new ClassBreaksRenderer();
pClassBreaksRenderer.Field = field;
pClassBreaksRenderer.BreakCount = breakCount;
pClassBreaksRenderer.MinimumBreak = minBreak;
// 根据中值计算间隔
double interval = (maxBreak - minBreak) / breakCount;
// 设置色带的分级数量
// 这里必须将原来的色带赋值给新声明的色带对象,否则会无法设置色带宽
IColorRamp pColorRamp = pColorRampD;
pColorRamp.Size = breakCount;
bool bCreateRamp;
pColorRamp.CreateRamp(out bCreateRamp);
if (!bCreateRamp)
throw new Exception("创建自定义分级色带失败!");
// 获取色带颜色枚举
IEnumColors pEnumColors = pColorRamp.Colors;
pEnumColors.Reset();
// 当前断点值
double currentBreak = minBreak;
// 遍历每个分隔符并进行符号化
/*
* 由于我这里渲染的是线,所以用的LineFillSymbol
* 要根据不同需求来选择点、线、面的填充符号
*/
ILineFillSymbol pLineFillSymbol;
// 判断是否要反转色带
if (isInvert == true)
{
List listColors = new List();
IColor pColor = pEnumColors.Next();
while (pColor != null)
{
listColors.Add(pColor);
pColor = pEnumColors.Next();
}
/*
* 这里尝试过将 i 赋值为 breakCount - 1 从分级断点的最后一个开始设置
* 但是会有问题,所以颜色会变成色带枚举的单一颜色
* 所以先存储为一个List,进行逆向取值,实现反转
*/
for (int i = 0; i < breakCount; i++)
{
// 设置断点
pClassBreaksRenderer.set_Break(i, currentBreak);
// 创建线填充样式并设置颜色
pLineFillSymbol = new LineFillSymbolClass();
pLineFillSymbol.Color = listColors[breakCount - i - 1];
pLineFillSymbol.LineSymbol.Width = 5;
// 添加样式
pClassBreaksRenderer.set_Symbol(i, pLineFillSymbol as ISymbol);
// 根据间隔递增
currentBreak += interval;
}
}
else
{
IColor pColor = pEnumColors.Next();
for (int i = 0; i < breakCount; i++)
{
// 设置断点
pClassBreaksRenderer.set_Break(i, currentBreak);
// 创建线填充样式并设置颜色
pLineFillSymbol = new LineFillSymbolClass();
pLineFillSymbol.Color = pColor;
pLineFillSymbol.LineSymbol.Width = 5;
// 添加样式
pClassBreaksRenderer.set_Symbol(i, pLineFillSymbol as ISymbol);
// 根据间隔递增
currentBreak += interval;
pColor = pEnumColors.Next();
}
}
// 设置图层的渲染方式
pGeoFeatureLayer.Renderer = (IFeatureRenderer)pClassBreaksRenderer;
}
///
/// 矢量分级符号化渲染2(自动分级)
///
/// 图层
/// 字段
/// 分级数
/// 色带对象
/// 是否反转
public static void GraduatedColorsRender2(ILayer pLayer, string fieldName, int breakCount, IColorRamp pColorRampD, bool isInvert)
{
IFeatureLayer pFeatureLayer = (IFeatureLayer)pLayer;
IGeoFeatureLayer pGeoFeatLayer = (IGeoFeatureLayer)pLayer;
IFeatureClass pFeatureClass = pFeatureLayer.FeatureClass;
ITable pTable = (ITable)pFeatureClass;
IBasicHistogram pBasicHistogram = new BasicTableHistogramClass();
ITableHistogram pTableHistogram = (ITableHistogram)pBasicHistogram;
pTableHistogram.Field = fieldName;
pTableHistogram.Table = pTable;
object dataValues;
object dataFrequency;
pBasicHistogram.GetHistogram(out dataValues, out dataFrequency);
IClassifyGEN pClassifyGEN = new QuantileClass();
int numClass = breakCount;
pClassifyGEN.Classify(dataValues, dataFrequency, ref numClass);
double[] classes = (double[])pClassifyGEN.ClassBreaks;
long classesCount = long.Parse(classes.GetUpperBound(0).ToString());
IClassBreaksRenderer pClassBreaksRenderer = new ClassBreaksRendererClass();
pClassBreaksRenderer.Field = fieldName;
pClassBreaksRenderer.MinimumBreak = classes[0];
pClassBreaksRenderer.SortClassesAscending = true;
// 设置着色对象的分级数目
pClassBreaksRenderer.BreakCount = int.Parse(classesCount.ToString());
// 设置色带的分级数量
IColorRamp pColorRamp = pColorRampD;
pColorRamp.Size = breakCount;
bool bCreateRamp;
pColorRamp.CreateRamp(out bCreateRamp);
if (!bCreateRamp)
throw new Exception("创建自定义分级色带失败!");
// 获取色带颜色枚举
IEnumColors pEnumColors = pColorRamp.Colors;
pEnumColors.Reset();
IClassBreaksUIProperties pUIProperties = (IClassBreaksUIProperties)pClassBreaksRenderer;
pUIProperties.ColorRamp = "Custom";
ILineFillSymbol pLineFillSymbol;
if (isInvert == true)
{
List listColors = new List();
IColor pColor = pEnumColors.Next();
while (pColor != null)
{
listColors.Add(pColor);
pColor = pEnumColors.Next();
}
for (int breakIndex = 0; breakIndex < classesCount; breakIndex++)
{
pClassBreaksRenderer.set_Label(breakIndex, classes[breakIndex] + "-" + classes[breakIndex + 1]);
pUIProperties.set_LowBreak(breakIndex, classes[breakIndex]);
pLineFillSymbol = new LineFillSymbolClass();
pColor = pEnumColors.Next();
pLineFillSymbol.Color = listColors[Convert.ToInt32(classesCount) - breakIndex - 1];
pLineFillSymbol.LineSymbol.Width = 5;
pClassBreaksRenderer.set_Symbol(breakIndex, (ISymbol)pLineFillSymbol);
pClassBreaksRenderer.set_Break(breakIndex, classes[breakIndex + 1]);
}
}
else
{
IColor pColor;
for (int breakIndex = 0; breakIndex < classesCount; breakIndex++)
{
pClassBreaksRenderer.set_Label(breakIndex, classes[breakIndex] + "-" + classes[breakIndex + 1]);
pUIProperties.set_LowBreak(breakIndex, classes[breakIndex]);
pLineFillSymbol = new LineFillSymbolClass();
pColor = pEnumColors.Next();
pLineFillSymbol.Color = pColor;
pLineFillSymbol.LineSymbol.Width = 5;
pClassBreaksRenderer.set_Symbol(breakIndex, (ISymbol)pLineFillSymbol);
pClassBreaksRenderer.set_Break(breakIndex, classes[breakIndex + 1]);
}
}
pGeoFeatLayer.Renderer = (IFeatureRenderer)pClassBreaksRenderer;
}
用色带(ColorRamp)对栅格数据进行拉伸渲染,实现起来比较简单,不用遍历要素赋值设色,而且Engine直接提供了一个IRasterStretchColorRampRenderer接口,可以直接传入色带进行拉伸,效果如下
同时,参照CSDN里一个博主的栅格数据色带选择器方法,实现了一下。
地址传送:https://blog.csdn.net/u013471015/article/details/80800648
栅格色带拉伸渲染代码:
///
/// 栅格符号化渲染(色带)
///
/// 栅格对象
/// 色带对象
public static void StretchedRender(IRasterLayer pRasterLayer, IColorRamp pColorRamp)
{
IRasterStretchColorRampRenderer pStretchRenderer = new RasterStretchColorRampRendererClass();
IRasterRenderer pRasterRenderer = (IRasterRenderer)pStretchRenderer;
// 设置渲染器属性
pRasterRenderer.Raster = pRasterLayer.Raster;
pRasterRenderer.Update();
pStretchRenderer.BandIndex = 0;
pStretchRenderer.ColorRamp = pColorRamp;
pRasterRenderer.Update();
// 设置拉伸类型
IRasterStretch pStretchType = (IRasterStretch)pRasterRenderer;
pStretchType.StretchType = esriRasterStretchTypesEnum.esriRasterStretch_PercentMinimumMaximum;
pStretchType.StandardDeviationsParam = 2;
pRasterLayer.Renderer = pStretchRenderer as IRasterRenderer;
}
注意:①需要先将传入的图层对象添加到地图控件中,再进行渲染和刷新。
注意:②如果地图控件(axMapControl)和目录控件(TOCControl)有关联,就要刷新一下TOCControl,图层的符号样式才会显示:axTOCControl.Update()
aliasName是要素类的原始命名,layerName是要素类加载到图层中的图层名。
如果修改了图层名,layerName是会变的,而aliasName不会变, 这里要注意名称判别,否则会找不到数据。
for (int i = 0; i < axMapControl.LayerCount; i++)
{
string aliasName = pFeatureLayer.FeatureClass.AliasName.ToString();
string layerName = axMapControl.get_Layer(i).Name;
// 注意:aliasName可能不等于layerName
}
这里做一个延伸,通过IFeature对象查找对应的图层名称
///
/// 根据要素获得对应的图层名称
///
/// 地图对象
/// 要素对象
/// 图层名称
public static string GetLayerNameByFeature(AxMapControl axMapControl, IFeature pFeature)
{
int index = -1;
IFeatureClass pFeatureClass = pFeature.Class as IFeatureClass;
for (int i = 0; i < axMapControl.Map.LayerCount; i++)
{
IFeatureLayer pFeatureLayer = axMapControl.get_Layer(i) as IFeatureLayer;
IFeatureClass pFeatureClass2 = pFeatureLayer.FeatureClass;
if (pFeatureClass == pFeatureClass2)
{
index = i;
break;
}
}
if(index == -1)
return "";
return axMapControl.Map.get_Layer(index).Name;
}
axMapControl图上拉框、点选等等操作的最常用三要素组合:
axMapControl_OnMouseDown事件 + axMapControl.CurrentTool工具 + 自定义操作
①axMapControl_OnMouseDown事件:
string mapOperate = ""; // 判别地图点击事件
///
/// 地图鼠标单击事件
///
private void axMapControl1_OnMouseDown(object sender, IMapControlEvents2_OnMouseDownEvent e)
{
if (e.button == 1)
{
switch (mapOperate)
{
case "selection":
IPoint point = new PointClass();
IGeometry pGeometry = point as IGeometry;
axMapControl.Map.SelectByShape(pGeometry, null, false);
axMapControl.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeoSelection, null, null);
break;
}
}
}
②axMapControl.CurrentTool工具 (写在自己的方法里):
mapOperate = "selection";
axMapControl.CurrentTool = null;
ControlsSelectFeaturesTool pCSFT = new ControlsSelectFeaturesToolClass();
pCSFT.OnCreate(axMapControl.Object);
axMapControl.CurrentTool = pCSFT as ITool;
③自定义操作(这里的Selectable属性用于控制图层是否可以被选中):
IFeatureLayer pFeatureLayer = pLayer as IFeatureLayer;
pFeatureLayer.Selectable = true;
这里只列举了文本标注和符号标注,可以自己写一个标注样式管理器,用于设置标注的字体、内容、颜色、大小等属性。
这里所说的标注,其实是Element元素数据,在ArcGIS的视图中显示的数据有两种,一种是地理数据,也就是栅格、矢量等;第二种就是元素,即Element。在地图上,除去地理数据以外的全部数据,都是Element数据。
Engine提供了ITextElement接口,可以在地图上标注文本元素,用户能够决定文本元素的位置、大小、内容、字体等,用于临时标注比如某个地块、某个点等的含义或注释。
*这里最好创建一个自定义的Base Tool工具
*然后在自己写的方法里调用
axMapControl.CurrentTool = null;
ICommand tool = new TextLabel();
tool.OnCreate(axMapControl.Object);
axMapControl.CurrentTool = tool as ITool;
*创建文本标注代码如下(写在自定义的Base Tool工具中,当然自己重新写一个方法来调用也可):
public override void OnMouseDown(int Button, int Shift, int X, int Y)
{
if (Button == 1)
{
ITextSymbol pTextSymbol;
pTextSymbol = new TextSymbolClass();
pTextSymbol.Size = 10;
stdole.IFontDisp pFont;
pFont = new stdole.StdFontClass() as stdole.IFontDisp;
// 字体可以用VS自带的FontDialog来获取
pFont.Name = "黑体";
pTextSymbol.Font = pFont;
IColor pColor;
IRgbColor pRgbColor = new RgbColorClass();
// 颜色可以用VS自带的ColorDialog来获取
pRgbColor.Red = 255;
pRgbColor.Green = 255;
pRgbColor.Blue = 255;
pColor = pRgbColor as IColor;
pTextSymbol.Color = pColor;
pTextElement.Text = "内容";
pTextElement.Symbol = pTextSymbol;
// 转为IElement用于添加到视图中
IElement pEle;
pEle = pTextElement as IElement;
IPoint pt = new PointClass();
pt = axMapControl.ActiveView.ScreenDisplay.DisplayTransformation.ToMapPoint(X, Y);
pEle.Geometry = pt;
IGraphicsContainer pGraphicsContainer = axMapControl.ActiveView.FocusMap as IGraphicsContainer;
pGraphicsContainer.AddElement(pEle, 0);
axMapControl.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, null);
}
}
Engine提供了IPictureMarkerSymbol接口,可以加载bmp位图,用于带有图片信息的标注。
*创建一个自定义的Base Tool工具方法同文本标注。
*创建符号标注代码如下:
IPoint pStopsPoint = new PointClass();
// 这里的X,Y指的是鼠标在空间参考下的坐标位置
pStopsPoint = axMapControl.ActiveView.ScreenDisplay.DisplayTransformation.ToMapPoint(X, Y);
IGraphicsContainer pGrap = axMapControl.ActiveView as IGraphicsContainer;
IColor pColor;
IRgbColor pRgbColor = new RgbColorClass();
pRgbColor.Red = 255;
pRgbColor.Green = 255;
pRgbColor.Blue = 255;
pColor = pRgbColor as IColor;
IPictureMarkerSymbol pms = new PictureMarkerSymbolClass();
pms.BitmapTransparencyColor = pColor;
// 加载自己的bmp文件路径
string bmpPath = "*.bmp";
// 添加自定义图片
pms.CreateMarkerSymbolFromFile(esriIPictureType.esriIPictureBitmap, bmpPath);
pms.Size = 18;
IMarkerElement pMarkerEle = new MarkerElementClass();
pMarkerEle.Symbol = pms as IMarkerSymbol;
pStopsPoint.SpatialReference = axMapControl.ActiveView.FocusMap.SpatialReference;
IElement pEle = pMarkerEle as IElement;
pEle.Geometry = pStopsPoint;
pGrap.AddElement(pEle, 1);
axMapControl.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, null);
Environment:Windows 7及以上
Language:C#
IDE:Visual Studio 2012
SDK:ArcGIS Engine 10.2
最近要转WebGIS了,不知什么时候能再碰Engine。只怕无法再有这种情怀,优美得共你同时在这世界。