您的位置:首页 > 其它

如何解决栅格色彩拉伸后TocControl里的图例不能更新的问题

2012-09-19 16:55 459 查看
关于栅格图层色彩拉伸,有很多例子,网上也可以找到各种资料,但是所有的资料都没有解决一个问题,那就是只说如何做拉伸,但是做色彩拉伸以后的图例更新问题一直没有正解。最早提出这个问题的帖子,在这里:http://forums.esri.com/thread.asp?c=93&f=1170&t=191617#848069,但是答案却一直空缺着,本文就来说明一下如何解决这个问题。

首先说一下如何让做栅格色彩拉伸,请看下面的代码:

IRasterLayer pRasterLayer = wndMap.CustomProperty as IRasterLayer;
                IRasterRenderer pRasterRender = pRasterLayer.Renderer;
                IRasterRenderer pNewRasterRender = null;

                IRgbColor pFromColor = new RgbColorClass();
                pFromColor.RGB = 0xffffff;
                IRgbColor pToColor = new RgbColorClass();
                pToColor.RGB = 0x000000;
                IAlgorithmicColorRamp pAlgorithmColorRamp = new AlgorithmicColorRampClass();
                pAlgorithmColorRamp.Size = 256;
                pAlgorithmColorRamp.FromColor = pFromColor;
                pAlgorithmColorRamp.ToColor = pToColor;
                bool bColorRampCreated = false;
                pAlgorithmColorRamp.CreateRamp(out bColorRampCreated);

                IRasterStretchColorRampRenderer pRasterStretchColorRamp = new RasterStretchColorRampRendererClass();
                pNewRasterRender = pRasterStretchColorRamp as IRasterRenderer;
                pNewRasterRender.Raster = pRasterLayer.Raster;
                pRasterStretchColorRamp.BandIndex = 0;
                pRasterStretchColorRamp.ColorRamp = pAlgorithmColorRamp;
                IRasterStretch pRasterStretch = pNewRasterRender as IRasterStretch;
                pRasterStretch.StretchType = esriRasterStretchTypesEnum.esriRasterStretch_MinimumMaximum;

                pNewRasterRender.Update();
                pRasterLayer.Renderer = pNewRasterRender;
这是基本的处理方式,这里出于使示例整洁完整使用的是一个自定义的色带。更为详尽的示例,请参考这里:http://www.gisall.com/html/59/26859-2432.html做色彩拉伸时,通常使用的色带是ArcGIS SymbologyControl里的预定义色带,加载的类型为esriSymbologyStyleClass.esriStyleClassColorRamps。可以将SymbologyControl里选中的色带直接转换为IColorRamp,然后作为IRasterStretchColorRampRenderer的ColorRamp。基本流程清除了,但问题也会凸显出来,那就是TocControl里的图例并不会自动显示色带。那么问题在哪里呢?下面来看一下AE附带的示例里相关的例子里是怎么做的,下面是AE的C#例子"SymbologyControlColorRamps"里对矢量图层做分段设色处理的代码:

private void button2_Click(object sender, System.EventArgs e)
		{
			//Create a new ClassBreaksRenderer and set properties
			m_classBreaksRenderer = new ClassBreaksRenderer();
			m_classBreaksRenderer.Field = comboBox1.SelectedItem.ToString();
			m_classBreaksRenderer.BreakCount = Convert.ToInt32(textBox1.Text);
			m_classBreaksRenderer.MinimumBreak = Convert.ToDouble(textBox2.Text);

			//Calculate the class interval by a simple mean value
			double interval = (Convert.ToDouble(textBox3.Text) - m_classBreaksRenderer.MinimumBreak) / m_classBreaksRenderer.BreakCount;

			//Get the color ramp
			IColorRamp colorRamp = (IColorRamp) m_styleGalleryItem.Item;
			//Set the size of the color ramp and recreate it
			colorRamp.Size = Convert.ToInt32(textBox1.Text);
			bool createRamp;
			colorRamp.CreateRamp(out createRamp);

			//Get the enumeration of colors from the color ramp
			IEnumColors enumColors = colorRamp.Colors;
			enumColors.Reset();
			double currentBreak = m_classBreaksRenderer.MinimumBreak;

			ISimpleFillSymbol simpleFillSymbol;
			//Loop rhough each class break
			for (int i = 0; i <= m_classBreaksRenderer.BreakCount-1; i++)
			{
				//Set class break
				m_classBreaksRenderer.set_Break(i,currentBreak);
				//Create simple fill symbol and set color
				simpleFillSymbol = new SimpleFillSymbolClass();
				simpleFillSymbol.Color = enumColors.Next();
				//Add symbol to renderer
				m_classBreaksRenderer.set_Symbol(i, (ISymbol)simpleFillSymbol);
				currentBreak += interval;
			}

			//Hide the form
			this.Hide();
		}


可以看到,这里面很重要的一点就是逐一设置了图例的符号。从这里,我们可以受到一点启发,那就是我们的栅格拉伸处理,是不是也需要做这样的一个处理。可以看到RasterStretchColorRampRender实现了ILegendInfo接口,而ILegendInfo接口就是用来管理图层图例的接口。据此,我们就需要详细研究一下ILegendInfo对象在做完上面的栅格色彩拉伸后有什么变化。经过跟踪发现,执行栅格拉伸后,ILegendInfo接口对象始终含有一个LegendGroup,而这个LegendGroup则含有三个LegendItem,查看这三个LegendItem的Label发现正是图层图例里列出的“高值”,"中间值“,”低值“,因此可以推断他们就是解决图例色带问题的核心。研究ILegendCalss接口,发现里面果然有Symbol成员,直觉告诉我们,应该修改这个属性。查找所有实现了ISymbol接口的类,发现IColorRampSymbol最有嫌疑。通过使用ArcMap***一个彩色拉伸图层,然后保存为MXD文档并用自己的程序加载,对比发现,果然自己做拉伸后所有LegendItem的Symbol都是null,而ArcMap做拉伸后LegendItem的Symbol都有值,并且可以转换为IColorRampSymbol,这样问题似乎已经浮出水面了,于是我们来添加下面的一段处理代码:

ILegendInfo pLengendInfo = m_RasterStretchColorRampRenderer  as ILegendInfo;
                ILegendGroup pLegendGroup = pLengendInfo.get_LegendGroup(0);
                IColorRamp pColorRamp = m_StyleGalleryItem.Item as IColorRamp;
                for (int j = 0; j < pLegendGroup.ClassCount; j++)
                {
                    ILegendClass pLegendClass = pLegendGroup.get_Class(j);
                    pLegendClass.Symbol = new ESRI.ArcGIS.Carto.ColorRampSymbolClass();
                    ISymbol pSymbol = pLegendClass.Symbol;
                    IColorRampSymbol pColorRampSymbol = pSymbol as IColorRampSymbol;
                    pColorRampSymbol.ColorRamp = pColorRamp;
                    pLegendClass.Symbol = pColorRampSymbol as ISymbol;
                }
                (m_RasterStretchColorRampRenderer as IRasterRenderer).Update();

很遗憾,图例中的色带出现了,但是并不是我们想看到的那样。继续探索,发现关于IColorRampSymbol接口,AE的帮助里几乎找不到任何有用的说明,于是我们不得不发挥想象力,考虑一下如果你是设计这个接口的人,你会怎么去做。很明显,栅格拉伸后的图例由三个LegendItem组成,每一个都带有一个Symbol,而这个Symbol都是IColorRampSymbol,但是这个色带符号很长,需要横跨三个图例项,唯一的办法就是把它分成3份,于是我们可能需要一个标记来告诉这三个图例项,他们分别应该对应这个色带符号的那一部分。据此,再来研究一下IColorRampSymbol接口,发现里面有两个属性非常可疑,一个是ColorRampInLegendGroup,一个是LegendClassIndex,很明显,作为一个图例项的成员,肯定知道自己的Index,但是这里却要多加这样一个属性,所以问题可能就在这里了。关于这个ColorRampInLegendGroup属性,网上以及AE的帮助里找不到任何有用的信息,所以也只好用猜的了。直白的来说,根据字面意思,这个属性的意思就是”图例组的色带“,所以我们可以猜测到实际处理中,这个图例组实际上使用的是一个色带,每个图例项也都是用这个色带,唯一需要做的就是用一个标记来标注每个图例项对应色带的哪里。下面就再做验证,仍然查看ArcMap下***的正确的色彩拉伸结果,发现三个图例项果然都使用同一个IColorRamp对象,于是问题就明朗了,毋庸置疑,LegendClassIndex的作用,正是我们所猜测的那样。于是对图例更新代码做一些修改,如下:

IColorRamp pColorRamp = m_StyleGalleryItem.Item as IColorRamp;
                m_RasterStretchColorRampRenderer.ColorRamp = pColorRamp;
                (m_RasterStretchColorRampRenderer as IRasterRenderer).Update();
                ILegendInfo pLengendInfo = m_RasterStretchColorRampRenderer as ILegendInfo;
                ILegendGroup pLegendGroup = pLengendInfo.get_LegendGroup(0);
                for (int j = 0; j < pLegendGroup.ClassCount; j++)
                {
                    ILegendClass pLegendClass = pLegendGroup.get_Class(j);
                    pLegendClass.Symbol = new ESRI.ArcGIS.Carto.ColorRampSymbolClass();
                    ISymbol pSymbol = pLegendClass.Symbol;
                    IColorRampSymbol pColorRampSymbol = pSymbol as IColorRampSymbol;
                    pColorRampSymbol.ColorRamp = pColorRamp;
                    pColorRampSymbol.ColorRampInLegendGroup = pColorRamp;
                    pColorRampSymbol.LegendClassIndex = j;
                    pLegendClass.Symbol = pColorRampSymbol as ISymbol;
                }
                (m_RasterStretchColorRampRenderer as IRasterRenderer).Update();

至此问题解决了。下面画个图,说明一下ColorRampSymbol与图例的关系:



简单说来,就是色彩拉伸后的图例实际上是一个由三个图例项组成的图例组,每个图例项都带有一个ColorRampSymbol,而借助这个ColorRampSymbol也可以指定整个图例组使用的色带,对于这个完整的色带,如何让图例项去自动对应呢,就是靠ColorRampSymbol的LengendClassIndex属性来完成的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: