About the Multivariate renderer Sample
[C#]
MultivariateRenderer.cs
using System;
using System.Collections;
using System.Data;
using System.Diagnostics;
using System.Runtime.InteropServices;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Display;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Geometry;
namespace MultivariateRenderers
{
public enum EColorCombinationType: int
{
enuComponents,
enuCIELabColorRamp,
enuLabLChColorRamp,
enuRGBAverage,
enuCIELabMatrix
}
[Guid("6A921DB3-5D31-4D85-9857-687CEDBC0D29")]
[ClassInterface(ClassInterfaceType.None)]
[ComVisible(true)]
[ProgId("MultiVariateRenderers.MultiVariateRendererCS")]
public class MultivariateRenderer : ExportSupport, IExportSupport, IFeatureRenderer, IMultivariateRenderer, ILegendInfo, IPersistVariant, IRotationRenderer, ITransparencyRenderer
{
// class definition for MultivariateRenderer, a custom multivariate feature renderer
// consisting of
// data members
private EColorCombinationType m_eColorCombinationMethod = EColorCombinationType.enuComponents;
private IFeatureRenderer m_pShapePatternRend;
private IFeatureRenderer m_pColorRend1;
private IFeatureRenderer m_pColorRend2;
private IFeatureRenderer m_pSizeRend;
// for the renderer's TOC and legend entry
// current implementation is simple, but could be extended
private ILegendGroup[] m_pLegendGroups;
private string m_sRotationField;
private esriSymbolRotationType m_eRotationType = esriSymbolRotationType.esriRotateSymbolGeographic;
private string m_sTransparencyField;
private IFeatureRenderer m_pMainRend; // as renderers are assigned, use this to keep track of which one has the base symbols
private esriGeometryType m_ShapeType;
private IFeatureClass m_pFeatureClass;
private IQueryFilter m_pQueryFilter;
private long[,] m_OLEColorMatrix = new long[4,4];
public MultivariateRenderer()
{
}
~MultivariateRenderer()
{
m_pShapePatternRend = null;
m_pColorRend1 = null;
m_pColorRend2 = null;
}
public void CreateLegend()
{
// NOT IMPL
}
public bool CanRender(IFeatureClass featClass, IDisplay Display)
{
// only use this renderer if we have points, lines, or polygons
return (featClass.ShapeType == esriGeometryType.esriGeometryPoint) | (featClass.ShapeType == esriGeometryType.esriGeometryPolyline) | (featClass.ShapeType == esriGeometryType.esriGeometryPolygon);
}
public void Draw(IFeatureCursor cursor, esriDrawPhase DrawPhase, IDisplay Display, ITrackCancel trackCancel)
{
string ActiveErrorHandler = null;
try
{
// loop through and draw each feature
IFeature pFeat = null;
IFeatureRenderer pRend = null;
bool bContinue = false;
// do not draw features if no display
if (Display == null)
return;
// we can't draw without somewhere to get our base symbols from
if (m_pMainRend == null)
return;
if (m_pSizeRend != null)
{
// size varies
if (m_ShapeType == esriGeometryType.esriGeometryPoint | m_ShapeType == esriGeometryType.esriGeometryPolyline)
{
if (DrawPhase == esriDrawPhase.esriDPGeography)
{
// draw symbols in order from large to small
DrawSymbolsInOrder(cursor, DrawPhase, Display, trackCancel);
}
}
else if (m_ShapeType == esriGeometryType.esriGeometryPolygon)
{
if (DrawPhase == esriDrawPhase.esriDPAnnotation)
{
// draw primary symbology from large to small
DrawSymbolsInOrder(cursor, DrawPhase, Display, trackCancel);
}
else if (DrawPhase == esriDrawPhase.esriDPGeography)
{
// draw background symbology
pFeat = cursor.NextFeature();
bContinue = true;
// while there are still more features and drawing has not been cancelled
IFillSymbol pBackFillSym;
while ((pFeat != null) & (bContinue == true))
{
// draw the feature
IFeatureDraw pFeatDraw = pFeat as IFeatureDraw;
if (m_pSizeRend is IClassBreaksRenderer)
{
IClassBreaksRenderer pCBRend = m_pSizeRend as IClassBreaksRenderer;
pBackFillSym = pCBRend.BackgroundSymbol;
}
else
{
IProportionalSymbolRenderer pPropRend = m_pSizeRend as IProportionalSymbolRenderer;
pBackFillSym = pPropRend.BackgroundSymbol;
}
Display.SetSymbol(pBackFillSym as ISymbol);
//implementation of IExportSupport
BeginFeature(pFeat, Display);
pFeatDraw.Draw(DrawPhase, Display, pBackFillSym as ISymbol, true, null, esriDrawStyle.esriDSNormal);
//implementation of IExportSupport
GenerateExportInfo(pFeat, Display);
EndFeature(Display);
pFeat = cursor.NextFeature();
if (trackCancel != null)
bContinue = trackCancel.Continue();
}
}
else
{
Marshal.ThrowExceptionForHR(147500037); //E_FAIL
}
}
}
else
{
// size does not vary
if (DrawPhase != esriDrawPhase.esriDPGeography)
{
Marshal.ThrowExceptionForHR(147500037); //E_FAIL
}
else
DrawSymbols(cursor, DrawPhase, Display, trackCancel);
}
}
catch
{
}
}
public IFeatureIDSet ExclusionSet
{
set
{
// NOT IMPL
}
}
public void PrepareFilter(IFeatureClass fc, IQueryFilter queryFilter)
{
// prepare filter for drawing
// must add OID
queryFilter.AddField(fc.OIDFieldName);
m_ShapeType = fc.ShapeType;
if (m_ShapeType == esriGeometryType.esriGeometryPoint)
{
if (m_sRotationField != null)
{
if (m_sRotationField != "")
{
queryFilter.AddField(m_sRotationField);
}
}
}
// save the fc and the query filter so that multiple cursors can be built in DrawSymbols
m_pFeatureClass = fc;
m_pQueryFilter = queryFilter;
// prepare filters on constituent renderers so I can use SymbolByFeature in Draw
if (m_pShapePatternRend != null)
m_pShapePatternRend.PrepareFilter(fc, queryFilter);
if (m_pColorRend1 != null)
m_pColorRend1.PrepareFilter(fc, queryFilter);
if (m_pColorRend2 != null)
m_pColorRend2.PrepareFilter(fc, queryFilter);
if (m_pSizeRend != null)
m_pSizeRend.PrepareFilter(fc, queryFilter);
// if we're combining colors from two (sequential) quantitative schemes, build color matrix now
// this gives flexibility to extend in future
// in current impl. we determine combined color based on two colors, one from each constituent
// ClassBreaksRenderer. so, we could determine color on demand when drawing. but, by creating
// the color matrix here and storing for later use, we leave open the possibility of swapping in
// different logic for determining combined colors based on all known colors in each constituent
// renderer, not just the colors for the given feature
if ((m_pColorRend1 != null) & (m_pColorRend2 != null))
{
if (! (m_eColorCombinationMethod == EColorCombinationType.enuComponents))
BuildColorMatrix();
}
//implementation of IExportSupport
AddExportFields(fc, queryFilter);
}
bool IFeatureRenderer.get_RenderPhase(ESRI.ArcGIS.esriSystem.esriDrawPhase DrawPhase)
{
return (DrawPhase == esriDrawPhase.esriDPGeography) | (DrawPhase == esriDrawPhase.esriDPAnnotation);
}
ESRI.ArcGIS.Display.ISymbol IFeatureRenderer.get_SymbolByFeature(ESRI.ArcGIS.Geodatabase.IFeature Feature)
{
return GetFeatureSymbol(Feature);
}
ESRI.ArcGIS.Carto.ILegendGroup ILegendInfo.get_LegendGroup(int Index)
{
string strHeading = null;
ILegendInfo pLegendInfo = null;
switch (Index)
{
case 0:
pLegendInfo = m_pMainRend as ILegendInfo;
if (m_pMainRend == m_pShapePatternRend)
strHeading = "Shape/Pattern: ";
else if (m_pMainRend == m_pSizeRend)
strHeading = "Size: ";
else
strHeading = "Color 1: ";
break;
case 1:
if (m_pShapePatternRend != null)
{
if (m_pSizeRend != null)
{
pLegendInfo = m_pSizeRend as ILegendInfo;
strHeading = "Size: ";
}
else
{
pLegendInfo = m_pColorRend1 as ILegendInfo;
strHeading = "Color 1: ";
}
}
else
{
if (m_pSizeRend != null)
{
pLegendInfo = m_pColorRend1 as ILegendInfo;
strHeading = "Color 1: ";
}
else
{
pLegendInfo = m_pColorRend2 as ILegendInfo;
strHeading = "Color 2: ";
}
}
break;
case 2:
pLegendInfo = m_pColorRend1 as ILegendInfo;
strHeading = "Color 1: ";
break;
case 3:
pLegendInfo = m_pColorRend2 as ILegendInfo;
strHeading = "Color 2: ";
break;
}
ILegendGroup pLegendGroup = null;
pLegendGroup = pLegendInfo.get_LegendGroup(0);
//pLegendGroup.Heading = strHeading & pLegendGroup.Heading
return pLegendGroup;
}
public int LegendGroupCount
{
get
{
ILegendInfo pLegInfo = null;
int n = 0;
n = 0;
if (m_pSizeRend != null)
{
pLegInfo = m_pSizeRend as ILegendInfo;
if (pLegInfo.get_LegendGroup(0) != null)
n = n + 1;
}
if (m_pShapePatternRend != null)
{
pLegInfo = m_pShapePatternRend as ILegendInfo;
if (pLegInfo.get_LegendGroup(0) != null)
n = n + 1;
}
if (m_pColorRend1 != null)
{
pLegInfo = m_pColorRend1 as ILegendInfo;
if (pLegInfo.get_LegendGroup(0) != null)
n = n + 1;
}
if (m_pColorRend2 != null & ! (m_pColorRend2 == m_pColorRend1))
{
//If Not m_pColorRend2 Is Nothing Then
pLegInfo = m_pColorRend2 as ILegendInfo;
if (pLegInfo.get_LegendGroup(0) != null)
n = n + 1;
}
return n;
}
}
public ILegendItem LegendItem
{
get
{
return null;
}
}
public bool SymbolsAreGraduated
{
get
{
return false;
}
set
{
// NOT IMPL
}
}
public UID ID
{
get
{
UID pUID = new UID();
pUID.Value = "MultivariateRenderers.MultiVariateRendererCS";
//pUID.Value = ClassId
return pUID;
}
}
public void Load(IVariantStream Stream)
{
//load the persisted parameters of the renderer
m_eColorCombinationMethod = (EColorCombinationType)Stream.Read();
m_pShapePatternRend = Stream.Read() as IFeatureRenderer;
m_pColorRend1 = Stream.Read() as IFeatureRenderer;
m_pColorRend2 = Stream.Read() as IFeatureRenderer;
m_pSizeRend = Stream.Read() as IFeatureRenderer;
//m_pLegendGroups = = Stream.Read
m_sRotationField = (string)Stream.Read();
m_eRotationType = (esriSymbolRotationType)Stream.Read();
m_sTransparencyField = (String)Stream.Read();
m_pMainRend = Stream.Read() as IFeatureRenderer;
//CreateLegend() ' not needed now
}
public void Save(IVariantStream Stream)
{
//persist the settings for the renderer
Stream.Write(m_eColorCombinationMethod);
Stream.Write(m_pShapePatternRend);
Stream.Write(m_pColorRend1);
Stream.Write(m_pColorRend2);
Stream.Write(m_pSizeRend);
//Stream.Write(m_pLegendGroups)
Stream.Write(m_sRotationField);
Stream.Write(m_eRotationType);
Stream.Write(m_sTransparencyField);
Stream.Write(m_pMainRend);
}
private ISymbol GetFeatureSymbol(IFeature pFeat)
{
ISymbol pSym = null;
// get base symbol
pSym = m_pMainRend.get_SymbolByFeature(pFeat);
// modify base symbol as necessary
if ((m_pSizeRend != null) && (! (m_pMainRend == m_pSizeRend)) && (pSym != null))
pSym = ApplySize(pSym, pFeat);
if (((m_pColorRend1 != null) | (m_pColorRend2 != null)) && (pSym != null))
pSym = ApplyColor(pSym, pFeat);
if (((m_ShapeType == esriGeometryType.esriGeometryPoint) | ((m_ShapeType == esriGeometryType.esriGeometryPolygon) & pSym is IMarkerSymbol)) && (pSym != null))
{
if (m_sRotationField != null)
{
if ((m_sRotationField != "") && (m_sRotationField != null))
{
pSym = ApplyRotation(pSym as IMarkerSymbol, pFeat as IFeature) as ISymbol;
}
}
}
// support for point, line, and poly features
if (m_sTransparencyField != null)
{
if (m_sTransparencyField != "")
{
pSym = ApplyTransparency(pSym);
}
}
return pSym;
}
private IFeatureCursor SortData(IFeatureCursor pCursor, ITrackCancel pTrackCancel)
{
// sort in descending by value
ITable pTable = null;
pTable = m_pFeatureClass as ITable;
ITableSort pTableSort = null;
pTableSort = new TableSort();
pTableSort.Table = pTable;
pTableSort.Cursor = pCursor as ICursor;
//set up the query filter.
IQueryFilter pQF = null;
pQF = new QueryFilter();
pQF.SubFields = "*";
pQF.WhereClause = m_pQueryFilter.WhereClause;
pTableSort.QueryFilter = pQF;
IProportionalSymbolRenderer pPSRend = null;
pPSRend = m_pSizeRend as IProportionalSymbolRenderer;
string strValueField = null;
strValueField = pPSRend.Field;
pTableSort.Fields = strValueField;
pTableSort.set_Ascending(strValueField, false);
IDataNormalization pDataNorm = null;
pDataNorm = pPSRend as IDataNormalization;
if (pDataNorm.NormalizationType == esriDataNormalization.esriNormalizeByField)
{
// comparison is not simple comparison of field values, use callback to do custom compare
// get normalization field and add to table sort
string strFields = "";
strFields = strFields + strValueField;
string strNormField = null;
strNormField = pDataNorm.NormalizationField;
strFields = strFields + ",";
strFields = strFields + strNormField;
pTableSort.Fields = strFields;
pTableSort.set_Ascending(strNormField, false);
// create new custom table call sort object and connect to the TableSort object
ITableSortCallBack pTableSortCallBack = null;
pTableSortCallBack = new SortCallBack(pTable.Fields.FindField(strValueField), pTable.Fields.FindField(strNormField));
pTableSort.Compare = pTableSortCallBack;
}
// call the sort
pTableSort.Sort(pTrackCancel);
// retrieve the sorted rows
IFeatureCursor pSortedCursor = null;
pSortedCursor = pTableSort.Rows as IFeatureCursor;
return pSortedCursor;
}
private void DrawSymbolsInOrder(IFeatureCursor Cursor, esriDrawPhase drawPhase, IDisplay Display, ITrackCancel trackCancel)
{
// this sub draws either markers or line symbols from large small so that the smallest symbols will be drawn on top
// in graduated symbol case, a cursor is built and parsed n times for n size classes
// in proportional symbol case, symbols are sorted and drawn from largest to smallest
int iSizeIndex = 0;
int iCurrentDrawableSymbolIndex = 0;
IFeatureCursor pMyCursor = null;
IFeature pFeat = null;
IFeatureDraw pFeatDraw = null;
bool bContinue = true;
ISymbol pSizeSym = null;
ISymbol pDrawSym = null;
IFeatureCursor pSortedCursor = null;
if (m_pSizeRend is IProportionalSymbolRenderer)
{
// sort
pSortedCursor = SortData(Cursor, trackCancel);
// draw
pFeat = pSortedCursor.NextFeature();
while (pFeat != null)
{
pDrawSym = GetFeatureSymbol(pFeat);
// draw the feature
pFeatDraw = pFeat as IFeatureDraw;
Display.SetSymbol(pDrawSym);
//implementation of IExportSupport
BeginFeature(pFeat, Display);
pFeatDraw.Draw(drawPhase, Display, pDrawSym, true, null, esriDrawStyle.esriDSNormal);
//implementation of IExportSupport
GenerateExportInfo(pFeat, Display);
EndFeature(Display);
// get next feature
pFeat = pSortedCursor.NextFeature();
if (trackCancel != null)
bContinue = trackCancel.Continue();
}
}
else
{
IClassBreaksRenderer pSizeCBRend = null;
pSizeCBRend = m_pSizeRend as IClassBreaksRenderer;
pMyCursor = Cursor;
for (iCurrentDrawableSymbolIndex = (pSizeCBRend.BreakCount - 1); iCurrentDrawableSymbolIndex >= 0; iCurrentDrawableSymbolIndex--)
{
// do not build a cursor the 1st time because we already have one
if (iCurrentDrawableSymbolIndex < (pSizeCBRend.BreakCount - 1))
{
// build pMyCursor
pMyCursor = m_pFeatureClass.Search(m_pQueryFilter, true);
}
pFeat = pMyCursor.NextFeature();
while (pFeat != null)
{
// check to see if we will draw in this pass
pSizeSym = m_pSizeRend.get_SymbolByFeature(pFeat);
iSizeIndex = GetSymbolIndex(pSizeSym, pSizeCBRend);
if (iSizeIndex == iCurrentDrawableSymbolIndex)
{
// go ahead and draw the symbol
// get symbol to draw
pDrawSym = GetFeatureSymbol(pFeat);
// draw the feature
pFeatDraw = pFeat as IFeatureDraw;
Display.SetSymbol(pDrawSym);
//implementation of IExportSupport
BeginFeature(pFeat, Display);
pFeatDraw.Draw(drawPhase, Display, pDrawSym, true, null, esriDrawStyle.esriDSNormal);
//implementation of IExportSupport
GenerateExportInfo(pFeat, Display);
EndFeature(Display);
if (trackCancel != null)
bContinue = trackCancel.Continue();
}
pFeat = pMyCursor.NextFeature();
}
} // increment DOWN to next symbol size
}
}
private void DrawSymbols(IFeatureCursor Cursor, esriDrawPhase drawPhase, IDisplay Display, ITrackCancel trackCancel)
{
IFeature pFeat = null;
IFeatureDraw pFeatDraw = null;
bool bContinue = true;
ISymbol pDrawSym = null;
pFeat = Cursor.NextFeature();
bContinue = true;
// while there are still more features and drawing has not been cancelled
while ((pFeat != null) & (bContinue == true))
{
// get symbol to draw
pDrawSym = GetFeatureSymbol(pFeat);
// draw the feature
pFeatDraw = pFeat as IFeatureDraw;
Display.SetSymbol(pDrawSym);
//implementation of IExportSupport
BeginFeature(pFeat, Display);
pFeatDraw.Draw(drawPhase, Display, pDrawSym, true, null, esriDrawStyle.esriDSNormal);
//implementation of IExportSupport
GenerateExportInfo(pFeat, Display);
EndFeature(Display);
// get next feature
pFeat = Cursor.NextFeature();
if (trackCancel != null)
bContinue = trackCancel.Continue();
}
}
private ESRI.ArcGIS.Display.IColor GetCombinedColor(IColor pColor1, IColor pColor2, EColorCombinationType eCombinationMethod)
{
return GetCombinedColor(pColor1, pColor2, eCombinationMethod, null);
}
private ESRI.ArcGIS.Display.IColor GetCombinedColor(IColor pColor1, IColor pColor2, EColorCombinationType eCombinationMethod, IColor pOriginColor)
{
// combines the input colors based on m_eColorCombinationMethod
// (11/08/04) -- RGB and enuLabLChColorRamp aren't used by GUI
IColor pOutColor = null;
long MyOLE_COLOR = 0; // As OLE_COLOR in VB6
IRgbColor pMainRGBColor = null;
IRgbColor pVariationRGBColor = null;
IRgbColor pMergedRGBColor = null;
bool bOK = false;
IAlgorithmicColorRamp pAlgorithmicCR = null;
// if either of the colors are null, then don't run the color through any algorithm,
// instead, just return the other color. if both are null, then return a null color
if (pColor1.NullColor)
{
pOutColor = pColor2;
}
else if (pColor2.NullColor)
{
pOutColor = pColor1;
}
else if (eCombinationMethod == EColorCombinationType.enuComponents)
{
// HSV components
// create a new HSV color
IHsvColor pHSVDrawColor = null;
pHSVDrawColor = new HsvColor();
// get HSV values from Color1 and Color2 and assign to pHSVDrawColor
IHsvColor pHSVColor1 = null;
IHsvColor pHSVColor2 = null;
// (new 4/27/04) didn't think I had to do this...
//pHSVColor1 = pColor1
//pHSVColor2 = pColor2
pHSVColor1 = new HsvColor();
pHSVColor1.RGB = pColor1.RGB;
pHSVColor2 = new HsvColor();
pHSVColor2.RGB = pColor2.RGB;
pHSVDrawColor.Hue = pHSVColor1.Hue;
pHSVDrawColor.Saturation = pHSVColor2.Saturation;
pHSVDrawColor.Value = pHSVColor2.Value;
pOutColor = pHSVDrawColor;
}
else if (eCombinationMethod == EColorCombinationType.enuRGBAverage)
{
// use additive color model to merge the two colors
MyOLE_COLOR = pColor1.RGB;
pMainRGBColor = new RgbColor();
pMainRGBColor.RGB = (int)MyOLE_COLOR;
MyOLE_COLOR = pColor2.RGB;
pVariationRGBColor = new RgbColor();
pVariationRGBColor.RGB = (int)MyOLE_COLOR;
// merged color = RGB average of the two colors
pMergedRGBColor = new RgbColor();
pMergedRGBColor.Red = (pMainRGBColor.Red + pVariationRGBColor.Red) / 2;
pMergedRGBColor.Green = (pMainRGBColor.Green + pVariationRGBColor.Green) / 2;
pMergedRGBColor.Blue = (pMainRGBColor.Blue + pVariationRGBColor.Blue) / 2;
pOutColor = pMergedRGBColor;
}
else if ((eCombinationMethod == EColorCombinationType.enuCIELabColorRamp) | (eCombinationMethod == EColorCombinationType.enuLabLChColorRamp))
{
// use color ramp and take central color between the two colors
pAlgorithmicCR = new AlgorithmicColorRamp();
if (m_eColorCombinationMethod == EColorCombinationType.enuCIELabColorRamp)
pAlgorithmicCR.Algorithm = esriColorRampAlgorithm.esriCIELabAlgorithm;
else
pAlgorithmicCR.Algorithm = esriColorRampAlgorithm.esriLabLChAlgorithm;
pAlgorithmicCR.Size = 3;
pAlgorithmicCR.FromColor = pColor1;
pAlgorithmicCR.ToColor = pColor2;
pAlgorithmicCR.CreateRamp(out bOK);
pOutColor = pAlgorithmicCR.get_Color(1); // middle color in ramp
}
else // EColorCombinationType.enuCIELabMatrix
{
double[] iLab1 = new double[4]; // L, a, b values for Color1
double[] iLab2 = new double[4]; // L, a, b values for Color2
double[] iLabOrig = new double[4]; // L, a, b values for pOriginColor
pColor1.GetCIELAB(out iLab1[0], out iLab1[1], out iLab1[2]);
pColor2.GetCIELAB(out iLab2[0], out iLab2[1], out iLab2[2]);
pOriginColor.GetCIELAB(out iLabOrig[0], out iLabOrig[1], out iLabOrig[2]);
double[] iLabOut = new double[4];
// add color1 vector and color2 vector, then subtract the origin color vector
iLabOut[0] = iLab1[0] + iLab2[0] - iLabOrig[0];
iLabOut[1] = iLab1[1] + iLab2[1] - iLabOrig[1];
iLabOut[2] = iLab1[2] + iLab2[2] - iLabOrig[2];
CorrectLabOutofRange(ref iLabOut[0], ref iLabOut[1], ref iLabOut[2]);
IHsvColor pHSVColor = null;
pHSVColor = new HsvColor();
pHSVColor.SetCIELAB(iLabOut[0], iLabOut[1], iLabOut[2]);
pOutColor = pHSVColor;
}
return pOutColor;
}
private void CorrectLabOutofRange(ref double L, ref double a, ref double b)
{
if (L > 100)
L = 100;
else if (L < 0)
L = 0;
if (a > 120)
a = 120;
else if (a < -120)
a = -120;
if (b > 120)
b = 120;
else if (b < -120)
b = -120;
}
private void RemoveLegend()
{
int i = 0;
if (m_pLegendGroups != null)
{
int tempFor1 = m_pLegendGroups.GetUpperBound(0);
for (i = 0; i <= tempFor1; i++)
{
m_pLegendGroups[i] = null;
}
}
}
private IFeatureRenderer CalcMainRend()
{
// consider using an internal array to keep track of active arrays in correct order, this will make it easier to implement ILegendInfo
if (m_pShapePatternRend != null)
{
if ((m_ShapeType == esriGeometryType.esriGeometryPolygon) & m_pSizeRend != null)
return m_pSizeRend;
else
return m_pShapePatternRend;
}
else if (m_pSizeRend != null)
return m_pSizeRend;
else if (m_pColorRend1 != null)
return m_pColorRend1;
else if (m_pColorRend2 != null)
return m_pColorRend2;
else
return null; // must have shape or color or size, if not you can't render...
}
public EColorCombinationType ColorCombinationMethod
{
get
{
return m_eColorCombinationMethod;
}
set
{
m_eColorCombinationMethod = value;
}
}
public ESRI.ArcGIS.Carto.IFeatureRenderer ColorRend1
{
get
{
return m_pColorRend1;
}
set
{
m_pColorRend1 = value;
m_pMainRend = CalcMainRend();
}
}
public ESRI.ArcGIS.Carto.IFeatureRenderer ColorRend2
{
get
{
return m_pColorRend2;
}
set
{
m_pColorRend2 = value;
}
}
public ESRI.ArcGIS.Carto.IFeatureRenderer ShapePatternRend
{
get
{
return m_pShapePatternRend;
}
set
{
m_pShapePatternRend = value;
m_pMainRend = CalcMainRend();
}
}
public ESRI.ArcGIS.Carto.IFeatureRenderer SizeRend
{
get
{
return m_pSizeRend;
}
set
{
m_pSizeRend = value;
m_pMainRend = CalcMainRend();
}
}
private IMarkerSymbol ApplyRotation(IMarkerSymbol pMarkerSym, IFeature pFeat)
{
double lAngle = 0;
int tempoindex = 0;
tempoindex = pFeat.Fields.FindField(m_sRotationField);
lAngle = Convert.ToDouble(pFeat.get_Value(tempoindex));
if (m_eRotationType == esriSymbolRotationType.esriRotateSymbolGeographic)
pMarkerSym.Angle = pMarkerSym.Angle - lAngle;
else
pMarkerSym.Angle = pMarkerSym.Angle + lAngle - 90;
return pMarkerSym;
}
private ISymbol ApplyTransparency(ISymbol pSym)
{
// TODO
return pSym;
}
private ISymbol ApplyColor(ISymbol pSym, IFeature pFeat)
{
try
{
ISymbol pSym1 = null;
ISymbol pSym2 = null;
IColor pColor = null;
IHsvColor pHSVColor = null;
if ((m_pColorRend1 != null) & (m_pColorRend2 != null)) // for now both color renderers need to be set to apply color
{
pSym1 = m_pColorRend1.get_SymbolByFeature(pFeat);
pSym2 = m_pColorRend2.get_SymbolByFeature(pFeat);
// only use GetCombinedColor for HSV component-type combination method
if (m_eColorCombinationMethod == EColorCombinationType.enuComponents)
{
pColor = GetCombinedColor(GetSymbolColor(pSym1), GetSymbolColor(pSym2), m_eColorCombinationMethod);
// Hue is good when I do this...
pHSVColor = pColor as IHsvColor;
//'MsgBox(Str(pHSVColor.Hue) & " " & Str(pHSVColor.Saturation) & " " & " " & Str(pHSVColor.Value()))
}
else
{
pColor = new RgbColor();
pColor.RGB = (int)m_OLEColorMatrix[GetSymbolIndex(pSym1 as ISymbol, m_pColorRend1 as IClassBreaksRenderer), GetSymbolIndex(pSym2 as ISymbol, m_pColorRend2 as IClassBreaksRenderer)];
}
if (pSym is IMarkerSymbol)
{
IMarkerSymbol pMarkerSym = null;
pMarkerSym = pSym as IMarkerSymbol;
pMarkerSym.Color = pColor;
}
else if (pSym is ILineSymbol)
{
ILineSymbol pLineSym = null;
pLineSym = pSym as ILineSymbol;
pLineSym.Color = pColor;
}
else if (pSym != null)
{
IFillSymbol pFillSym = null;
pFillSym = pSym as IFillSymbol;
pFillSym.Color = pColor;
}
}
return pSym;
return null;
}
catch
{
return null;
}
}
private ISymbol ApplySize(ISymbol pSym, IFeature pFeat)
{
if (pSym is IMarkerSymbol)
{
// Marker Symbol
IMarkerSymbol pTargetMarkerSym = null;
pTargetMarkerSym = pSym as IMarkerSymbol;
IMarkerSymbol pSourceMarkerSym = null;
pSourceMarkerSym = m_pSizeRend.get_SymbolByFeature(pFeat) as IMarkerSymbol;
if (pSourceMarkerSym != null)
{
pTargetMarkerSym.Size = pSourceMarkerSym.Size;
}
}
else
{
// Line Symbol
ILineSymbol pTargetLineSym = null;
pTargetLineSym = pSym as ILineSymbol;
ILineSymbol pSourceLineSym = null;
pSourceLineSym = m_pSizeRend.get_SymbolByFeature(pFeat) as ILineSymbol;
if (pSourceLineSym != null)
{
pTargetLineSym.Width = pSourceLineSym.Width;
}
}
return pSym;
}
public string RotationField
{
get
{
return m_sRotationField;
}
set
{
m_sRotationField = value;
}
}
public string TransparencyField
{
get
{
return m_sTransparencyField;
}
set
{
m_sTransparencyField = value;
}
}
public ESRI.ArcGIS.Carto.esriSymbolRotationType RotationType
{
get
{
return m_eRotationType;
}
set
{
m_eRotationType = value;
}
}
private int GetSymbolIndex(ISymbol pSym, IClassBreaksRenderer pRend)
{
// given an input symbol and a renderer, this function returns the index of
// the class that the symbol represents in the renderer
int i = 0;
int iNumBreaks = 0;
iNumBreaks = pRend.BreakCount;
i = 0;
ILegendInfo pLegendInfo = null;
pLegendInfo = pRend as ILegendInfo;
while (i < iNumBreaks - 1)
{
if (pLegendInfo.SymbolsAreGraduated)
{
// compare based on size
if (SymbolsAreSameSize(pSym, pRend.get_Symbol(i)))
break;
}
else
{
// compare based on color
if (SymbolsAreSameColor(pSym, pRend.get_Symbol(i)))
break;
}
i = i + 1;
}
return i;
// NOTE: for some reason we can't test that the symbol objects are the same, so above we do quick test for equal properties instead
//Do While (i < iNumBreaks - 1)
// If pSym Is pRend.Symbol(i) Then Exit Do
// i = i + 1
//Loop
//Return i
// (I think this only works for renderer that does Graduated symbols)
//If m_ShapeType = esriGeometryType.esriGeometryPoint Or m_ShapeType = esriGeometryType.esriGeometryPolygon Then
// ' determine the symbol index based on marker symbol size
// pInMarkerSym = pSym
// i = 0
// pClassMarkerSym = pRend.Symbol(0)
// dblSize = pClassMarkerSym.Size
// Do While (i < iNumBreaks - 1) And (pInMarkerSym.Size > dblSize)
// pClassMarkerSym = pRend.Symbol(i)
// dblSize = pClassMarkerSym.Size
// i = i + 1
// Loop
// iReturnVal = i
//Else ' m_shapetype = esriGeometryLine
// ' determine the symbol index based on line symbol width
// pInLineSym = pSym
// i = 0
// pClassLineSym = pRend.Symbol(0)
// dblWidth = pClassLineSym.Width
// Do While (i < iNumBreaks - 1) And (pInLineSym.Width > dblWidth)
// pClassLineSym = pRend.Symbol(i)
// dblSize = pClassLineSym.Width
// i = i + 1
// Loop
// iReturnVal = i
//End If
}
private bool SymbolsAreSameSize(ISymbol pSym1, ISymbol psym2)
{
if (pSym1 is IMarkerSymbol)
{
IMarkerSymbol pMS1 = null;
IMarkerSymbol pMS2 = null;
pMS1 = pSym1 as IMarkerSymbol;
pMS2 = psym2 as IMarkerSymbol;
return pMS1.Size == pMS2.Size;
}
else
{
ILineSymbol pLS1 = null;
ILineSymbol pLS2 = null;
pLS1 = pSym1 as ILineSymbol;
pLS2 = psym2 as ILineSymbol;
return pLS1.Width == pLS2.Width;
}
}
private bool SymbolsAreSameColor(ISymbol pSym1, ISymbol psym2)
{
IColor pColor1 = null;
IColor pColor2 = null;
pColor1 = GetSymbolColor(pSym1);
pColor2 = GetSymbolColor(psym2);
return pColor1.RGB == pColor2.RGB;
}
private void BuildColorMatrix()
{
try
{
// On Error GoTo ErrHand
IClassBreaksRenderer pCBRend1 = null;
IClassBreaksRenderer pCBRend2 = null;
pCBRend1 = m_pColorRend1 as IClassBreaksRenderer;
pCBRend2 = m_pColorRend2 as IClassBreaksRenderer;
int i = 0;
int j = 0;
IColor pColor1 = null;
IColor pColor2 = null;
IColor pColor = null;
if (m_eColorCombinationMethod == EColorCombinationType.enuCIELabMatrix)
{
// new (11/5/04)
// origin (CIELab average now, but would be better to extend both lines to intersection point,
// or average of points where they are closest)
pColor1 = GetSymbolColor(pCBRend1.get_Symbol(0));
pColor2 = GetSymbolColor(pCBRend2.get_Symbol(0));
pColor = GetCombinedColor(pColor1, pColor2, EColorCombinationType.enuCIELabColorRamp);
IColor pOriginColor = null;
pOriginColor = pColor;
m_OLEColorMatrix[i, j] = pColor.RGB;
// bottom edge (known)
int tempFor1 = pCBRend1.BreakCount;
for (i = 1; i < tempFor1; i++)
{
pColor = GetSymbolColor(pCBRend1.get_Symbol(i));
m_OLEColorMatrix[i, 0] = pColor.RGB;
}
// left edge (known)
int tempFor2 = pCBRend2.BreakCount;
for (j = 1; j < tempFor2; j++)
{
pColor = GetSymbolColor(pCBRend2.get_Symbol(j));
m_OLEColorMatrix[0, j] = pColor.RGB;
}
// remaining values (interpolated)
int tempFor3 = pCBRend1.BreakCount;
for (i = 1; i < tempFor3; i++)
{
int tempFor4 = pCBRend2.BreakCount;
for (j = 1; j < tempFor4; j++)
{
pColor1 = GetSymbolColor(pCBRend1.get_Symbol(i));
pColor2 = GetSymbolColor(pCBRend2.get_Symbol(j));
pColor = GetCombinedColor(pColor1, pColor2, EColorCombinationType.enuCIELabMatrix, pOriginColor);
m_OLEColorMatrix[i, j] = pColor.RGB;
//m_pColorMatrix(i, j) = GetCombinedColor(pColor1, pColor2)
}
}
}
else
{
int tempFor5 = pCBRend1.BreakCount;
for (i = 0; i < tempFor5; i++)
{
int tempFor6 = pCBRend2.BreakCount;
for (j = 0; j < tempFor6; j++)
{
pColor1 = GetSymbolColor(pCBRend1.get_Symbol(i));
pColor2 = GetSymbolColor(pCBRend2.get_Symbol(j));
pColor = GetCombinedColor(pColor1, pColor2, m_eColorCombinationMethod);
m_OLEColorMatrix[i, j] = pColor.RGB;
//m_pColorMatrix(i, j) = GetCombinedColor(pColor1, pColor2)
}
}
}
return;
}
catch
{
Console.WriteLine("error");
}
}
private IColor GetSymbolColor(ISymbol pSym)
{
IMarkerSymbol pMarkerSym = null;
ILineSymbol pLineSym = null;
IFillSymbol pFillSym = null;
IColor pColor = null;
if (pSym is IMarkerSymbol)
{
pMarkerSym = pSym as IMarkerSymbol;
pColor = pMarkerSym.Color;
}
else if (pSym is ILineSymbol)
{
pLineSym = pSym as ILineSymbol;
pColor = pLineSym.Color;
}
else
{
pFillSym = pSym as IFillSymbol;
pColor = pFillSym.Color;
}
return pColor;
}
}
//implementation of IExportSupport
// ExportSupport is a private helper class to help the renderer implement of IExportSupport. This class contains
// the reference to the ExportInfoGenerator object used by the renderer.
public class ExportSupport : IExportSupport
{
ISymbologyEnvironment2 m_symbologyEnvironment2;
IFeatureExportInfoGenerator m_exportInfoGenerator;
bool m_exportAttributes;
bool m_exportHyperlinks;
public ExportSupport()
{
m_exportAttributes = false;
m_exportHyperlinks = false;
}
~ExportSupport()
{
m_symbologyEnvironment2 = null;
m_exportInfoGenerator = null;
}
public void GetExportSettings()
{
m_exportAttributes = false;
m_exportHyperlinks = false;
if (m_exportInfoGenerator == null)
return;
if (m_symbologyEnvironment2 == null)
m_symbologyEnvironment2 = new SymbologyEnvironmentClass();
m_exportAttributes = m_symbologyEnvironment2.OutputGDICommentForFeatureAttributes;
m_exportHyperlinks = m_symbologyEnvironment2.OutputGDICommentForHyperlinks;
}
public void GenerateExportInfo(IFeature feature, IDisplay display)
{
if (m_exportInfoGenerator == null)
return;
if (m_exportAttributes)
m_exportInfoGenerator.GenerateFeatureInfo(feature, display);
if (m_exportHyperlinks)
m_exportInfoGenerator.GenerateHyperlinkInfo(feature, display);
}
public void GenerateExportInfo(IFeatureDraw featureDraw, IDisplay display)
{
if (m_exportInfoGenerator == null)
return;
if (m_exportAttributes)
m_exportInfoGenerator.GenerateFeatureInfo(featureDraw as IFeature, display);
if (m_exportHyperlinks)
m_exportInfoGenerator.GenerateHyperlinkInfo(featureDraw as IFeature, display);
}
public void AddExportFields(IFeatureClass fc, IQueryFilter queryFilter)
{
if (m_exportInfoGenerator == null)
return;
GetExportSettings();
if (m_exportAttributes || m_exportHyperlinks)
m_exportInfoGenerator.PrepareExportFilter(fc, queryFilter);
}
public void BeginFeature(IFeature feature, IDisplay display)
{
if (m_exportInfoGenerator == null)
return;
m_exportInfoGenerator.BeginFeature(feature, display);
}
public void EndFeature(IDisplay display)
{
if (m_exportInfoGenerator == null)
return;
m_exportInfoGenerator.EndFeature(display);
}
#region IExportSupport Members
public IFeatureExportInfoGenerator ExportInfo
{
set
{
m_exportInfoGenerator = value;
}
}
#endregion
}
[Guid("13137B0F-2255-46a4-9D6E-0A68FA560379")]
[ClassInterface(ClassInterfaceType.None)]
[ComVisible(true)]
[ProgId("MultiVariateRenderers.SortCallBack")]
public class SortCallBack : ITableSortCallBack
{
// class definition for SortCallBack which implements custom table sorting based on field / normalization field
// data members
private Microsoft.VisualBasic.VariantType m_value1;
private Microsoft.VisualBasic.VariantType m_value2;
private int m_iValueIndex;
private int m_iNormIndex;
public SortCallBack(int ValueIndex, int NormIndex)
{
m_iValueIndex = ValueIndex;
m_iNormIndex = NormIndex;
}
public int Compare(object value1, object value2, int FieldIndex, int fieldSortIndex)
{
int tempCompare = 0;
// sort normalized values
if (FieldIndex == m_iValueIndex)
{
m_value1 = (Microsoft.VisualBasic.VariantType)value1;
m_value2 = (Microsoft.VisualBasic.VariantType)value2;
return 0; // ?
}
if (FieldIndex == m_iNormIndex)
{
if (((double)value1 == 0) | ((double)value2 == 0)) // ?
return 0;
double dblNormedVal1 = 0;
double dblNormedVal2 = 0;
dblNormedVal1 = (double)m_value1 / (double)value1;
dblNormedVal2 = (double)m_value2 / (double)value2;
if (dblNormedVal1 > dblNormedVal2)
tempCompare = 1;
else if (dblNormedVal1 < dblNormedVal2)
tempCompare = -1;
else
tempCompare = 0;
}
return tempCompare;
}
}
} //end of root namespace
[Visual Basic .NET]
MultivariateRenderer.vb
Imports ESRI.ArcGIS.Carto
Imports ESRI.ArcGIS.Display
Imports ESRI.ArcGIS.esriSystem
Imports ESRI.ArcGIS.Geodatabase
Imports ESRI.ArcGIS.Geometry
Public Enum EColorCombinationType
enuComponents
enuCIELabColorRamp
enuLabLChColorRamp
enuRGBAverage
enuCIELabMatrix
End Enum
<ComClass(MultivariateRenderer.ClassId, MultivariateRenderer.InterfaceId, MultivariateRenderer.EventsId)> _
Public Class MultivariateRenderer
Inherits ExportSupport
' class definition for MultivariateRenderer, a custom multivariate feature renderer
' consisting of
Implements IFeatureRenderer ' all feature renderers must support this interface
Implements IMultivariateRenderer ' custom interface
Implements ILegendInfo ' for TOC and legend support
Implements IPersistVariant ' to support saving and loading .mxd and .lyr files that contain this renderer
Implements IRotationRenderer ' to support symbol rotation by field value
Implements ITransparencyRenderer ' we don't do anything real with this
#Region "COM GUIDs"
' These GUIDs provide the COM identity for this class
' and its COM interfaces. If you change them, existing
' clients will no longer be able to access the class.
Public Const ClassId As String = "6A921DB3-5D31-4D85-9857-687CEDBC0D29"
Public Const InterfaceId As String = "DDC4CD50-DF02-4B2F-9B85-DA87FDED9EA7"
Public Const EventsId As String = "36E15D76-2463-41DD-A673-0C83021AC30A"
#End Region
' data members
Private m_eColorCombinationMethod As EColorCombinationType = EColorCombinationType.enuComponents
Private m_pShapePatternRend As IFeatureRenderer
Private m_pColorRend1 As IFeatureRenderer
Private m_pColorRend2 As IFeatureRenderer
Private m_pSizeRend As IFeatureRenderer
' for the renderer's TOC and legend entry
' current implementation is simple, but could be extended
Private m_pLegendGroups() As ILegendGroup
Private m_sRotationField As String
Private m_eRotationType As esriSymbolRotationType = esriSymbolRotationType.esriRotateSymbolGeographic
Private m_sTransparencyField As String
Private m_pMainRend As IFeatureRenderer ' as renderers are assigned, use this to keep track of which one has the base symbols
Private m_ShapeType As esriGeometryType
Private m_pFeatureClass As IFeatureClass
Private m_pQueryFilter As IQueryFilter
Private m_OLEColorMatrix(3, 3) As Long
Private Const E_FAIL As Long = &H80004005
Public Sub New()
End Sub
Protected Overrides Sub Finalize()
m_pShapePatternRend = Nothing
m_pColorRend1 = Nothing
m_pColorRend2 = Nothing
MyBase.Finalize()
End Sub
Public Sub CreateLegend() Implements IMultivariateRenderer.CreateLegend
' NOT IMPL
' this is a place holder sub for logic that can be called that creates a more
' involved entry for the layer's TOC and legend entry
End Sub
Public Function CanRender(ByVal featClass As IFeatureClass, ByVal Display As IDisplay) As Boolean Implements IFeatureRenderer.CanRender
' only use this renderer if we have points, lines, or polygons
Return (featClass.ShapeType = esriGeometryType.esriGeometryPoint) Or _
(featClass.ShapeType = esriGeometryType.esriGeometryPolyline) Or _
(featClass.ShapeType = esriGeometryType.esriGeometryPolygon)
End Function
Public Sub Draw(ByVal cursor As IFeatureCursor, ByVal DrawPhase As esriDrawPhase, ByVal Display As IDisplay, ByVal trackCancel As ITrackCancel) Implements IFeatureRenderer.Draw
' loop through and draw each feature
Dim pFeat As IFeature
Dim pRend As IFeatureRenderer
Dim pFeatDraw As IFeatureDraw
Dim bContinue As Boolean
' do not draw features if no display
If (Display Is Nothing) Then
Exit Sub
End If
' we can't draw without somewhere to get our base symbols from
If (m_pMainRend Is Nothing) Then
Exit Sub
End If
If Not m_pSizeRend Is Nothing Then
' size varies
If m_ShapeType = esriGeometryType.esriGeometryPoint Or m_ShapeType = esriGeometryType.esriGeometryPolyline Then
If DrawPhase = esriDrawPhase.esriDPGeography Then
' draw symbols in order from large to small
DrawSymbolsInOrder(cursor, DrawPhase, Display, trackCancel)
End If
ElseIf m_ShapeType = esriGeometryType.esriGeometryPolygon Then
If (DrawPhase = esriDrawPhase.esriDPAnnotation) Then
' draw primary symbology from large to small
DrawSymbolsInOrder(cursor, DrawPhase, Display, trackCancel)
ElseIf (DrawPhase = esriDrawPhase.esriDPGeography) Then
' draw background symbology
pFeat = cursor.NextFeature
bContinue = True
' while there are still more features and drawing has not been cancelled
Dim pBackFillSym As IFillSymbol
Do While (Not pFeat Is Nothing) And (bContinue = True)
' draw the feature
pFeatDraw = pFeat
If TypeOf m_pSizeRend Is IClassBreaksRenderer Then
Dim pCBRend As IClassBreaksRenderer
pCBRend = m_pSizeRend
pBackFillSym = pCBRend.BackgroundSymbol
Else
Dim pPropRend As IProportionalSymbolRenderer
pPropRend = m_pSizeRend
pBackFillSym = pPropRend.BackgroundSymbol
End If
Display.SetSymbol(pBackFillSym)
'implementation of IExportSupport
BeginFeature(pFeat, Display)
pFeatDraw.Draw(DrawPhase, Display, pBackFillSym, True, Nothing, esriDrawStyle.esriDSNormal)
'implementation of IExportSupport
GenerateExportInfo(pFeat, Display)
EndFeature(Display)
pFeat = cursor.NextFeature
If Not trackCancel Is Nothing Then bContinue = trackCancel.[Continue]
Loop
Else
' raising this error makes the selection symbol draw for selected features
On Error GoTo 0
Err.Raise(E_FAIL)
End If
End If
Else
' size does not vary
If (DrawPhase <> esriDrawPhase.esriDPGeography) Then
' raising this error makes the selection symbol draw for selected features
On Error GoTo 0
Err.Raise(E_FAIL)
Else
DrawSymbols(cursor, DrawPhase, Display, trackCancel)
End If
End If
End Sub
Public WriteOnly Property ExclusionSet() As IFeatureIDSet Implements IFeatureRenderer.ExclusionSet
Set(ByVal Value As IFeatureIDSet)
' NOT IMPL
End Set
End Property
Public Sub PrepareFilter(ByVal fc As IFeatureClass, ByVal queryFilter As IQueryFilter) Implements IFeatureRenderer.PrepareFilter
' prepare filter for drawing
' must add OID
queryFilter.AddField(fc.OIDFieldName)
m_ShapeType = fc.ShapeType
If m_ShapeType = esriGeometryType.esriGeometryPoint Then
If Not m_sRotationField = "" Then
queryFilter.AddField(m_sRotationField)
End If
End If
' save the feature class and the query filter so that multiple cursors can be built in DrawSymbols
m_pFeatureClass = fc
m_pQueryFilter = queryFilter
' prepare filters on constituent renderers so I can use SymbolByFeature in Draw
If Not m_pShapePatternRend Is Nothing Then m_pShapePatternRend.PrepareFilter(fc, queryFilter)
If Not m_pColorRend1 Is Nothing Then m_pColorRend1.PrepareFilter(fc, queryFilter)
If Not m_pColorRend2 Is Nothing Then m_pColorRend2.PrepareFilter(fc, queryFilter)
If Not m_pSizeRend Is Nothing Then m_pSizeRend.PrepareFilter(fc, queryFilter)
' if we're combining colors from two (sequential) quantitative schemes, build color matrix now
' this gives flexibility to extend in future
' in current implementation we determine combined color based on two colors, one from each constituent
' ClassBreaksRenderer. so, we could determine color on demand when drawing. but, by creating
' the color matrix here and storing for later use, we leave open the possibility of swapping in
' different logic for determining combined colors based on all known colors in each constituent
' renderer, not just the colors for the given feature
If (Not m_pColorRend1 Is Nothing) And (Not m_pColorRend2 Is Nothing) Then
If Not m_eColorCombinationMethod = EColorCombinationType.enuComponents Then
BuildColorMatrix()
End If
End If
'implementation of IExportSupport
AddExportFields(fc, queryFilter)
End Sub
Public ReadOnly Property RenderPhase(ByVal DrawPhase As esriDrawPhase) As Boolean Implements IFeatureRenderer.RenderPhase
Get
Return (DrawPhase = esriDrawPhase.esriDPGeography) Or (DrawPhase = esriDrawPhase.esriDPAnnotation)
End Get
End Property
Public ReadOnly Property SymbolByFeature(ByVal Feature As IFeature) As ISymbol Implements IFeatureRenderer.SymbolByFeature
Get
Return GetFeatureSymbol(Feature)
End Get
End Property
Public ReadOnly Property LegendGroup(ByVal Index As Integer) As ILegendGroup Implements ILegendInfo.LegendGroup
Get
Dim pLegendInfo As ILegendInfo = Nothing
Dim strHeading As String
Select Case Index
Case 0
pLegendInfo = m_pMainRend
If m_pMainRend Is m_pShapePatternRend Then
strHeading = "Shape/Pattern: "
ElseIf m_pMainRend Is m_pSizeRend Then
strHeading = "Size: "
Else
strHeading = "Color 1: "
End If
Case 1
If Not m_pShapePatternRend Is Nothing Then
If Not m_pSizeRend Is Nothing Then
pLegendInfo = m_pSizeRend
strHeading = "Size: "
Else
pLegendInfo = m_pColorRend1
strHeading = "Color 1: "
End If
Else
If Not m_pSizeRend Is Nothing Then
pLegendInfo = m_pColorRend1
strHeading = "Color 1: "
Else
pLegendInfo = m_pColorRend2
strHeading = "Color 2: "
End If
End If
Case 2
pLegendInfo = m_pColorRend1
strHeading = "Color 1: "
Case 3
pLegendInfo = m_pColorRend2
strHeading = "Color 2: "
End Select
Dim pLegendGroup As ILegendGroup
pLegendGroup = pLegendInfo.LegendGroup(0)
'pLegendGroup.Heading = strHeading & pLegendGroup.Heading
Return pLegendGroup
End Get
End Property
Public ReadOnly Property LegendGroupCount() As Integer Implements ILegendInfo.LegendGroupCount
Get
Dim pLegInfo As ILegendInfo
Dim n As Integer
n = 0
If Not m_pSizeRend Is Nothing Then
pLegInfo = m_pSizeRend
If Not pLegInfo.LegendGroup(0) Is Nothing Then n = n + 1
End If
If Not m_pShapePatternRend Is Nothing Then
pLegInfo = m_pShapePatternRend
If Not pLegInfo.LegendGroup(0) Is Nothing Then n = n + 1
End If
If Not m_pColorRend1 Is Nothing Then
pLegInfo = m_pColorRend1
If Not pLegInfo.LegendGroup(0) Is Nothing Then n = n + 1
End If
If Not m_pColorRend2 Is Nothing And Not m_pColorRend2 Is m_pColorRend1 Then
'If Not m_pColorRend2 Is Nothing Then
pLegInfo = m_pColorRend2
If Not pLegInfo.LegendGroup(0) Is Nothing Then n = n + 1
End If
Return n
End Get
End Property
Public ReadOnly Property LegendItem() As ILegendItem Implements ILegendInfo.LegendItem
Get
Return Nothing
End Get
End Property
Public Property SymbolsAreGraduated() As Boolean Implements ILegendInfo.SymbolsAreGraduated
Get
Return False
End Get
Set(ByVal Value As Boolean)
' NOT IMPL
End Set
End Property
Public ReadOnly Property ID() As UID Implements IPersistVariant.ID
Get
Dim pUID As New UID
pUID.Value = "MultivariateRenderer"
'pUID.Value = ClassId
Return pUID
End Get
End Property
Public Sub Load(ByVal Stream As IVariantStream) Implements IPersistVariant.Load
'load the persisted parameters of the renderer
m_eColorCombinationMethod = Stream.Read
m_pShapePatternRend = Stream.Read
m_pColorRend1 = Stream.Read
m_pColorRend2 = Stream.Read
m_pSizeRend = Stream.Read
'm_pLegendGroups = = Stream.Read
m_sRotationField = Stream.Read
m_eRotationType = Stream.Read
m_sTransparencyField = Stream.Read
m_pMainRend = Stream.Read
'CreateLegend() ' not needed now
End Sub
Public Sub Save(ByVal Stream As IVariantStream) Implements IPersistVariant.Save
'persist the settings for the renderer
Stream.Write(m_eColorCombinationMethod)
Stream.Write(m_pShapePatternRend)
Stream.Write(m_pColorRend1)
Stream.Write(m_pColorRend2)
Stream.Write(m_pSizeRend)
'Stream.Write(m_pLegendGroups)
Stream.Write(m_sRotationField)
Stream.Write(m_eRotationType)
Stream.Write(m_sTransparencyField)
Stream.Write(m_pMainRend)
End Sub
Private Function GetFeatureSymbol(ByVal pFeat As IFeature) As ISymbol
Dim pSym As ISymbol
' get base symbol
pSym = m_pMainRend.SymbolByFeature(pFeat)
' modify base symbol as necessary
If (Not m_pSizeRend Is Nothing) And (Not m_pMainRend Is m_pSizeRend) And (Not pSym Is Nothing) Then
pSym = ApplySize(pSym, pFeat)
End If
If ((Not m_pColorRend1 Is Nothing) Or (Not m_pColorRend2 Is Nothing)) And (Not pSym Is Nothing) Then
pSym = ApplyColor(pSym, pFeat)
End If
If ((m_ShapeType = esriGeometryType.esriGeometryPoint) Or ((m_ShapeType = esriGeometryType.esriGeometryPolygon) And TypeOf pSym Is IMarkerSymbol)) And (Not pSym Is Nothing) Then
If m_sRotationField <> "" Then
pSym = ApplyRotation(pSym, pFeat)
End If
End If
If m_sTransparencyField <> "" Then
pSym = ApplyTransparency(pSym)
End If
'End If
Return pSym
End Function
Private Function SortData(ByVal pCursor As IFeatureCursor, ByVal pTrackCancel As ITrackCancel) As IFeatureCursor
' sort in descending by value
Dim pTable As ITable
pTable = m_pFeatureClass
Dim pTableSort As ITableSort
pTableSort = New TableSort
pTableSort.Table = pTable
pTableSort.Cursor = pCursor
' why do I have to do this?
Dim pQF As IQueryFilter
pQF = New QueryFilter
pQF.SubFields = "*"
pQF.WhereClause = m_pQueryFilter.WhereClause
pTableSort.QueryFilter = pQF
Dim pPSRend As IProportionalSymbolRenderer
pPSRend = m_pSizeRend
Dim strValueField As String
strValueField = pPSRend.Field
pTableSort.Fields = strValueField
pTableSort.Ascending(strValueField) = False
Dim pDataNorm As IDataNormalization
pDataNorm = pPSRend
If pDataNorm.NormalizationType = esriDataNormalization.esriNormalizeByField Then
' comparison is not simple comparison of field values, use callback to do custom compare
' get normalization field and add to table sort
Dim strFields As String = ""
strFields = strFields & strValueField
Dim strNormField As String
strNormField = pDataNorm.NormalizationField
strFields = strFields & ","
strFields = strFields & strNormField
pTableSort.Fields = strFields
pTableSort.Ascending(strNormField) = False
' create new custom table call sort object and connect to the TableSort object
Dim pTableSortCallBack As ITableSortCallBack
pTableSortCallBack = New SortCallBack(pTable.Fields.FindField(strValueField), pTable.Fields.FindField(strNormField))
pTableSort.Compare = pTableSortCallBack
End If
' call the sort
pTableSort.Sort(pTrackCancel)
' retrieve the sorted rows
Dim pSortedCursor As IFeatureCursor
pSortedCursor = pTableSort.Rows()
Return pSortedCursor
End Function
Private Sub DrawSymbolsInOrder(ByVal Cursor As IFeatureCursor, ByVal drawPhase As esriDrawPhase, ByVal Display As IDisplay, ByVal trackCancel As ITrackCancel)
' this sub draws either markers or line symbols from large small so that the smallest symbols will be drawn on top
' in graduated symbol case, a cursor is built and parsed n times for n size classes
' in proportional symbol case, symbols are sorted and drawn from largest to smallest
Dim iSizeIndex As Integer
Dim iCurrentDrawableSymbolIndex As Integer
Dim pMyCursor As IFeatureCursor
Dim pFeat As IFeature
Dim pFeatDraw As IFeatureDraw
Dim bContinue As Boolean = True
Dim pSizeSym As ISymbol
Dim pDrawSym As ISymbol
Dim pSortedCursor As IFeatureCursor
If TypeOf m_pSizeRend Is IProportionalSymbolRenderer Then
' sort
pSortedCursor = SortData(Cursor, trackCancel)
' draw
pFeat = pSortedCursor.NextFeature
Do While Not pFeat Is Nothing
pDrawSym = GetFeatureSymbol(pFeat)
' draw the feature
pFeatDraw = pFeat
Display.SetSymbol(pDrawSym)
'implementation of IExportSupport
BeginFeature(pFeat, Display)
pFeatDraw.Draw(drawPhase, Display, pDrawSym, True, Nothing, esriDrawStyle.esriDSNormal)
'implementation of IExportSupport
GenerateExportInfo(pFeat, Display)
EndFeature(Display)
' get next feature
pFeat = pSortedCursor.NextFeature
If Not trackCancel Is Nothing Then bContinue = trackCancel.[Continue]
Loop
Else
Dim pSizeCBRend As IClassBreaksRenderer
pSizeCBRend = m_pSizeRend
pMyCursor = Cursor
For iCurrentDrawableSymbolIndex = (pSizeCBRend.BreakCount - 1) To 0 Step -1
' do not build a cursor the 1st time because we already have one
If iCurrentDrawableSymbolIndex < (pSizeCBRend.BreakCount - 1) Then
' build pMyCursor
pMyCursor = m_pFeatureClass.Search(m_pQueryFilter, True)
End If
pFeat = pMyCursor.NextFeature
Do While Not pFeat Is Nothing
' check to see if we will draw in this pass
pSizeSym = m_pSizeRend.SymbolByFeature(pFeat)
iSizeIndex = GetSymbolIndex(pSizeSym, pSizeCBRend)
If (iSizeIndex = iCurrentDrawableSymbolIndex) Then
' go ahead and draw the symbol
' get symbol to draw
pDrawSym = GetFeatureSymbol(pFeat)
' draw the feature
pFeatDraw = pFeat
Display.SetSymbol(pDrawSym)
'implementation of IExportSupport
BeginFeature(pFeat, Display)
pFeatDraw.Draw(drawPhase, Display, pDrawSym, True, Nothing, esriDrawStyle.esriDSNormal)
'implementation of IExportSupport
GenerateExportInfo(pFeat, Display)
EndFeature(Display)
If Not trackCancel Is Nothing Then bContinue = trackCancel.[Continue]
End If
pFeat = pMyCursor.NextFeature
Loop
Next iCurrentDrawableSymbolIndex ' increment DOWN to next symbol size
End If
End Sub
Private Sub DrawSymbols(ByVal Cursor As IFeatureCursor, ByVal drawPhase As esriDrawPhase, ByVal Display As IDisplay, ByVal trackCancel As ITrackCancel)
Dim pFeat As IFeature
Dim pFeatDraw As IFeatureDraw
Dim bContinue As Boolean = True
Dim pDrawSym As ISymbol
pFeat = Cursor.NextFeature
bContinue = True
' while there are still more features and drawing has not been cancelled
Do While (Not pFeat Is Nothing) And (bContinue = True)
' get symbol to draw
pDrawSym = GetFeatureSymbol(pFeat)
' draw the feature
pFeatDraw = pFeat
Display.SetSymbol(pDrawSym)
'implementation of IExportSupport
BeginFeature(pFeat, Display)
pFeatDraw.Draw(drawPhase, Display, pDrawSym, True, Nothing, esriDrawStyle.esriDSNormal)
'implementation of IExportSupport
GenerateExportInfo(pFeat, Display)
EndFeature(Display)
' get next feature
pFeat = Cursor.NextFeature
If Not trackCancel Is Nothing Then bContinue = trackCancel.[Continue]
Loop
End Sub
Private Function GetCombinedColor(ByVal pColor1 As IColor, ByVal pColor2 As IColor, ByVal eCombinationMethod As EColorCombinationType, Optional ByVal pOriginColor As IColor = Nothing) As ESRI.ArcGIS.Display.IColor
' combines the input colors based on m_eColorCombinationMethod
Dim pOutColor As IColor
Dim MyOLE_COLOR As Long ' As OLE_COLOR in VB6
Dim pMainRGBColor As IRgbColor
Dim pVariationRGBColor As IRgbColor
Dim pMergedRGBColor As IRgbColor
Dim bOK As Boolean
Dim pAlgorithmicCR As IAlgorithmicColorRamp
' if either of the colors are null, then don't run the color through any algorithm,
' instead, just return the other color. if both are null, then return a null color
If pColor1.NullColor Then
pOutColor = pColor2
ElseIf pColor2.NullColor Then
pOutColor = pColor1
ElseIf eCombinationMethod = EColorCombinationType.enuComponents Then
' HSV components
' create a new HSV color
Dim pHSVDrawColor As IHsvColor
pHSVDrawColor = New HsvColor
' get HSV values from Color1 and Color2 and assign to pHSVDrawColor
Dim pHSVColor1 As IHsvColor
Dim pHSVColor2 As IHsvColor
pHSVColor1 = New HsvColor
pHSVColor1.RGB = pColor1.RGB
pHSVColor2 = New HsvColor
pHSVColor2.RGB = pColor2.RGB
pHSVDrawColor.Hue = pHSVColor1.Hue
pHSVDrawColor.Saturation = pHSVColor2.Saturation
pHSVDrawColor.Value = pHSVColor2.Value
pOutColor = pHSVDrawColor
ElseIf eCombinationMethod = EColorCombinationType.enuRGBAverage Then
' use additive color model to merge the two colors
MyOLE_COLOR = pColor1.RGB
pMainRGBColor = New RgbColor
pMainRGBColor.RGB = MyOLE_COLOR
MyOLE_COLOR = pColor2.RGB
pVariationRGBColor = New RgbColor
pVariationRGBColor.RGB = MyOLE_COLOR
' merged color = RGB average of the two colors
pMergedRGBColor = New RgbColor
pMergedRGBColor.Red = (pMainRGBColor.Red + pVariationRGBColor.Red) / 2
pMergedRGBColor.Green = (pMainRGBColor.Green + pVariationRGBColor.Green) / 2
pMergedRGBColor.Blue = (pMainRGBColor.Blue + pVariationRGBColor.Blue) / 2
pOutColor = pMergedRGBColor
ElseIf (eCombinationMethod = EColorCombinationType.enuCIELabColorRamp) Or (eCombinationMethod = EColorCombinationType.enuLabLChColorRamp) Then
' use color ramp and take central color between the two colors
pAlgorithmicCR = New AlgorithmicColorRamp
If m_eColorCombinationMethod = EColorCombinationType.enuCIELabColorRamp Then
pAlgorithmicCR.Algorithm = esriColorRampAlgorithm.esriCIELabAlgorithm
Else
pAlgorithmicCR.Algorithm = esriColorRampAlgorithm.esriLabLChAlgorithm
End If
pAlgorithmicCR.Size = 3
pAlgorithmicCR.FromColor = pColor1
pAlgorithmicCR.ToColor = pColor2
pAlgorithmicCR.CreateRamp(bOK)
pOutColor = pAlgorithmicCR.Color(1) ' middle color in ramp
Else ' EColorCombinationType.enuCIELabMatrix
Dim iLab1(3) As Double ' L, a, b values for Color1
Dim iLab2(3) As Double ' L, a, b values for Color2
Dim iLabOrig(3) As Double ' L, a, b values for pOriginColor
pColor1.GetCIELAB(iLab1(0), iLab1(1), iLab1(2))
pColor2.GetCIELAB(iLab2(0), iLab2(1), iLab2(2))
pOriginColor.GetCIELAB(iLabOrig(0), iLabOrig(1), iLabOrig(2))
Dim iLabOut(3) As Double
' add color1 vector and color2 vector, then subtract the origin color vector
iLabOut(0) = iLab1(0) + iLab2(0) - iLabOrig(0)
iLabOut(1) = iLab1(1) + iLab2(1) - iLabOrig(1)
iLabOut(2) = iLab1(2) + iLab2(2) - iLabOrig(2)
CorrectLabOutofRange(iLabOut(0), iLabOut(1), iLabOut(2))
Dim pHSVColor As IHsvColor
pHSVColor = New HsvColor
pHSVColor.SetCIELAB(iLabOut(0), iLabOut(1), iLabOut(2))
pOutColor = pHSVColor
End If
Return pOutColor
End Function
Private Sub CorrectLabOutofRange(ByRef L As Double, ByRef a As Double, ByRef b As Double)
If L > 100 Then
L = 100
ElseIf L < 0 Then
L = 0
End If
If a > 120 Then
a = 120
ElseIf a < -120 Then
a = -120
End If
If b > 120 Then
b = 120
ElseIf b < -120 Then
b = -120
End If
End Sub
Private Sub RemoveLegend()
Dim i As Integer
If Not m_pLegendGroups Is Nothing Then
For i = 0 To UBound(m_pLegendGroups)
m_pLegendGroups(i) = Nothing
Next i
End If
End Sub
Private Function CalcMainRend() As IFeatureRenderer
' consider using an internal array to keep track of active arrays in correct order, this will make it easier to implement ILegendInfo
If (Not m_pShapePatternRend Is Nothing) Then
If (m_ShapeType = esriGeometryType.esriGeometryPolygon) And Not m_pSizeRend Is Nothing Then
Return m_pSizeRend
Else
Return m_pShapePatternRend
End If
ElseIf (Not m_pSizeRend Is Nothing) Then
Return m_pSizeRend
ElseIf (Not m_pColorRend1 Is Nothing) Then
Return m_pColorRend1
ElseIf (Not m_pColorRend2 Is Nothing) Then
Return m_pColorRend2
Else
Return Nothing ' must have shape or color or size, if not you can't render...
End If
End Function
Public Property ColorCombinationMethod() As EColorCombinationType Implements IMultivariateRenderer.ColorCombinationMethod
Get
Return m_eColorCombinationMethod
End Get
Set(ByVal Value As EColorCombinationType)
m_eColorCombinationMethod = Value
End Set
End Property
Public Property ColorRend1() As ESRI.ArcGIS.Carto.IFeatureRenderer Implements IMultivariateRenderer.ColorRend1
Get
Return m_pColorRend1
End Get
Set(ByVal Value As ESRI.ArcGIS.Carto.IFeatureRenderer)
m_pColorRend1 = Value
m_pMainRend = CalcMainRend()
End Set
End Property
Public Property ColorRend2() As ESRI.ArcGIS.Carto.IFeatureRenderer Implements IMultivariateRenderer.ColorRend2
Get
Return m_pColorRend2
End Get
Set(ByVal Value As ESRI.ArcGIS.Carto.IFeatureRenderer)
m_pColorRend2 = Value
End Set
End Property
Public Property ShapePatternRend() As ESRI.ArcGIS.Carto.IFeatureRenderer Implements IMultivariateRenderer.ShapePatternRend
Get
Return m_pShapePatternRend
End Get
Set(ByVal Value As ESRI.ArcGIS.Carto.IFeatureRenderer)
m_pShapePatternRend = Value
m_pMainRend = CalcMainRend()
End Set
End Property
Public Property SizeRend() As ESRI.ArcGIS.Carto.IFeatureRenderer Implements IMultivariateRenderer.SizeRend
Get
Return m_pSizeRend
End Get
Set(ByVal Value As ESRI.ArcGIS.Carto.IFeatureRenderer)
m_pSizeRend = Value
m_pMainRend = CalcMainRend()
End Set
End Property
Private Function ApplyRotation(ByVal pMarkerSym As IMarkerSymbol, ByVal pFeat As IFeature) As IMarkerSymbol
Dim lAngle As Double
lAngle = Convert.ToDouble(pFeat.Value(pFeat.Fields.FindField(m_sRotationField)))
If m_eRotationType = esriSymbolRotationType.esriRotateSymbolGeographic Then
pMarkerSym.Angle = pMarkerSym.Angle - lAngle
Else
pMarkerSym.Angle = pMarkerSym.Angle + lAngle - 90
End If
Return pMarkerSym
End Function
Private Function ApplyTransparency(ByVal pSym As ISymbol) As ISymbol
' TODO
Return pSym
End Function
Private Function ApplyColor(ByVal pSym As ISymbol, ByVal pFeat As IFeature) As ISymbol
On Error GoTo ErrHand
Dim pSym1 As ISymbol
Dim pSym2 As ISymbol
Dim pColor As IColor
Dim pHSVColor As IHsvColor
If (Not m_pColorRend1 Is Nothing) And (Not m_pColorRend2 Is Nothing) Then ' for now both color renderers need to be set to apply color
pSym1 = m_pColorRend1.SymbolByFeature(pFeat)
pSym2 = m_pColorRend2.SymbolByFeature(pFeat)
' only use GetCombinedColor for HSV component-type combination method
If m_eColorCombinationMethod = EColorCombinationType.enuComponents Then
pColor = GetCombinedColor(GetSymbolColor(pSym1), GetSymbolColor(pSym2), m_eColorCombinationMethod)
pHSVColor = pColor
Else
'pColor = m_pColorMatrix(GetSymbolIndex(pSym1, m_pColorRend1), GetSymbolIndex(pSym2, m_pColorRend2))
pColor = New RgbColor
pColor.RGB = m_OLEColorMatrix(GetSymbolIndex(pSym1, m_pColorRend1), GetSymbolIndex(pSym2, m_pColorRend2))
End If
If TypeOf pSym Is IMarkerSymbol Then
Dim pMarkerSym As IMarkerSymbol
pMarkerSym = pSym
pMarkerSym.Color = pColor
ElseIf TypeOf pSym Is ILineSymbol Then
Dim pLineSym As ILineSymbol
pLineSym = pSym
pLineSym.Color = pColor
Else
Dim pFillSym As IFillSymbol
pFillSym = pSym
pFillSym.Color = pColor
End If
End If
Return pSym
Exit Function
ErrHand:
MsgBox("Apply Color " & Err.Description & "Line: " & Err.Erl)
End Function
Private Function ApplySize(ByVal pSym As ISymbol, ByVal pFeat As IFeature) As ISymbol
If TypeOf pSym Is IMarkerSymbol Then
' Marker Symbol
Dim pTargetMarkerSym As IMarkerSymbol
pTargetMarkerSym = pSym
Dim pSourceMarkerSym As IMarkerSymbol
pSourceMarkerSym = m_pSizeRend.SymbolByFeature(pFeat)
If Not (pSourceMarkerSym Is Nothing) Then
pTargetMarkerSym.Size = pSourceMarkerSym.Size
End If
Else
' Line Symbol
Dim pTargetLineSym As ILineSymbol
pTargetLineSym = pSym
Dim pSourceLineSym As ILineSymbol
pSourceLineSym = m_pSizeRend.SymbolByFeature(pFeat)
If Not (pSourceLineSym Is Nothing) Then
pTargetLineSym.Width = pSourceLineSym.Width
End If
End If
Return pSym
End Function
Public Property RotationField() As String Implements IRotationRenderer.RotationField
Get
Return m_sRotationField
End Get
Set(ByVal Value As String)
m_sRotationField = Value
End Set
End Property
Public Property TransparencyField() As String Implements ITransparencyRenderer.TransparencyField
Get
Return m_sTransparencyField
End Get
Set(ByVal Value As String)
m_sTransparencyField = Value
End Set
End Property
Public Property RotationType() As ESRI.ArcGIS.Carto.esriSymbolRotationType Implements IRotationRenderer.RotationType
Get
Return m_eRotationType
End Get
Set(ByVal Value As ESRI.ArcGIS.Carto.esriSymbolRotationType)
m_eRotationType = Value
End Set
End Property
Private Function GetSymbolIndex(ByVal pSym As ISymbol, ByVal pRend As IClassBreaksRenderer) As Integer
' given an input symbol and a renderer, this function returns the index of
' the class that the symbol represents in the renderer
Dim i As Integer
Dim iNumBreaks As Integer
iNumBreaks = pRend.BreakCount
i = 0
Dim pLegendInfo As ILegendInfo
pLegendInfo = pRend
Do While (i < iNumBreaks - 1)
If pLegendInfo.SymbolsAreGraduated Then
' compare based on size
If SymbolsAreSameSize(pSym, pRend.Symbol(i)) Then Exit Do
Else
' compare based on color
If SymbolsAreSameColor(pSym, pRend.Symbol(i)) Then Exit Do
End If
i = i + 1
Loop
Return i
End Function
Private Function SymbolsAreSameSize(ByVal pSym1 As ISymbol, ByVal psym2 As ISymbol) As Boolean
If TypeOf pSym1 Is IMarkerSymbol Then
Dim pMS1 As IMarkerSymbol
Dim pMS2 As IMarkerSymbol
pMS1 = pSym1
pMS2 = psym2
Return pMS1.Size = pMS2.Size
Else
Dim pLS1 As ILineSymbol
Dim pLS2 As ILineSymbol
pLS1 = pSym1
pLS2 = psym2
Return pLS1.Width = pLS2.Width
End If
End Function
Private Function SymbolsAreSameColor(ByVal pSym1 As ISymbol, ByVal psym2 As ISymbol) As Boolean
Dim pColor1 As IColor
Dim pColor2 As IColor
pColor1 = GetSymbolColor(pSym1)
pColor2 = GetSymbolColor(psym2)
Return pColor1.RGB = pColor2.RGB
End Function
Private Sub BuildColorMatrix()
On Error GoTo ErrHand
Dim pCBRend1 As IClassBreaksRenderer
Dim pCBRend2 As IClassBreaksRenderer
pCBRend1 = New ClassBreaksRenderer()
pCBRend2 = New ClassBreaksRenderer()
If ((TypeOf m_pColorRend1 Is IFeatureRenderer) And (TypeOf m_pColorRend2 Is IFeatureRenderer)) Then
pCBRend1 = CType(m_pColorRend1, IClassBreaksRenderer)
pCBRend2 = CType(m_pColorRend2, IClassBreaksRenderer)
Dim i As Integer
Dim j As Integer
Dim pColor1 As IColor
Dim pColor2 As IColor
Dim pColor As IColor
If m_eColorCombinationMethod = EColorCombinationType.enuCIELabMatrix Then
' new (11/5/04)
' origin (CIELab average now, but would be better to extend both lines to intersection point,
' or average of points where they are closest)
pColor1 = GetSymbolColor(pCBRend1.Symbol(0))
pColor2 = GetSymbolColor(pCBRend2.Symbol(0))
pColor = GetCombinedColor(pColor1, pColor2, EColorCombinationType.enuCIELabColorRamp)
Dim pOriginColor As IColor
pOriginColor = pColor
m_OLEColorMatrix(i, j) = pColor.RGB
' bottom edge (known)
For i = 1 To pCBRend1.BreakCount - 1
pColor = GetSymbolColor(pCBRend1.Symbol(i))
m_OLEColorMatrix(i, 0) = pColor.RGB
Next
' left edge (known)
For j = 1 To pCBRend2.BreakCount - 1
pColor = GetSymbolColor(pCBRend2.Symbol(j))
m_OLEColorMatrix(0, j) = pColor.RGB
Next
' remaining values (interpolated)
For i = 1 To pCBRend1.BreakCount - 1
For j = 1 To pCBRend2.BreakCount - 1
pColor1 = GetSymbolColor(pCBRend1.Symbol(i))
pColor2 = GetSymbolColor(pCBRend2.Symbol(j))
pColor = GetCombinedColor(pColor1, pColor2, EColorCombinationType.enuCIELabMatrix, pOriginColor)
m_OLEColorMatrix(i, j) = pColor.RGB
Next j
Next i
Else
For i = 0 To pCBRend1.BreakCount - 1
For j = 0 To pCBRend2.BreakCount - 1
pColor1 = GetSymbolColor(pCBRend1.Symbol(i))
pColor2 = GetSymbolColor(pCBRend2.Symbol(j))
pColor = GetCombinedColor(pColor1, pColor2, m_eColorCombinationMethod)
m_OLEColorMatrix(i, j) = pColor.RGB
Next j
Next i
End If
End If
Exit Sub
ErrHand:
MsgBox(Err.Description)
End Sub
Private Function GetSymbolColor(ByVal pSym As ISymbol) As IColor
Dim pMarkerSym As IMarkerSymbol
Dim pLineSym As ILineSymbol
Dim pFillSym As IFillSymbol
Dim pColor As IColor
If TypeOf pSym Is IMarkerSymbol Then
pMarkerSym = pSym
pColor = pMarkerSym.Color
ElseIf TypeOf pSym Is ILineSymbol Then
pLineSym = pSym
pColor = pLineSym.Color
ElseIf Not pSym Is Nothing Then
pFillSym = pSym
pColor = pFillSym.Color
Else
pColor = Nothing
End If
Return pColor
End Function
End Class
'implementation of IExportSupport
' ExportSupport is a private helper class to help the renderer implement of IExportSupport. This class contains
' the reference to the ExportInfoGenerator object used by the renderer.
Public Class ExportSupport
Implements IExportSupport
Dim m_symbologyEnvironment2 As ISymbologyEnvironment2
Dim m_exportInfoGenerator As IFeatureExportInfoGenerator
Dim m_exportAttributes As Boolean
Dim m_exportHyperlinks As Boolean
Public WriteOnly Property ExportInfo() As ESRI.ArcGIS.Carto.IFeatureExportInfoGenerator Implements ESRI.ArcGIS.Carto.IExportSupport.ExportInfo
Set(ByVal value As ESRI.ArcGIS.Carto.IFeatureExportInfoGenerator)
m_exportInfoGenerator = value
End Set
End Property
Public Sub New()
m_exportAttributes = False
m_exportHyperlinks = False
End Sub
Protected Overrides Sub Finalize()
m_symbologyEnvironment2 = Nothing
m_exportInfoGenerator = Nothing
MyBase.Finalize()
End Sub
Public Sub GetExportSettings()
m_exportAttributes = False
m_exportHyperlinks = False
If m_exportInfoGenerator Is Nothing Then Exit Sub
If m_symbologyEnvironment2 Is Nothing Then
m_symbologyEnvironment2 = New SymbologyEnvironment
End If
m_exportAttributes = m_symbologyEnvironment2.OutputGDICommentForFeatureAttributes
m_exportHyperlinks = m_symbologyEnvironment2.OutputGDICommentForHyperlinks
End Sub
Public Sub GenerateExportInfo(ByRef feature As IFeature, ByRef display As IDisplay)
If m_exportInfoGenerator Is Nothing Then Exit Sub
If m_exportAttributes Then m_exportInfoGenerator.GenerateFeatureInfo(feature, display)
If m_exportHyperlinks Then m_exportInfoGenerator.GenerateHyperlinkInfo(feature, display)
End Sub
Public Sub GenerateExportInfo(ByRef featureDraw As IFeatureDraw, ByRef display As IDisplay)
If m_exportInfoGenerator Is Nothing Then Exit Sub
Dim feature As IFeature
feature = featureDraw
If m_exportAttributes Then m_exportInfoGenerator.GenerateFeatureInfo(feature, display)
If m_exportHyperlinks Then m_exportInfoGenerator.GenerateHyperlinkInfo(feature, display)
End Sub
Public Sub AddExportFields(ByRef fc As IFeatureClass, ByRef queryFilter As IQueryFilter)
If m_exportInfoGenerator Is Nothing Then Exit Sub
GetExportSettings()
If m_exportAttributes Or m_exportHyperlinks Then
m_exportInfoGenerator.PrepareExportFilter(fc, queryFilter)
End If
End Sub
Public Sub BeginFeature(ByRef feature As IFeature, ByRef display As IDisplay)
If m_exportInfoGenerator Is Nothing Then Exit Sub
m_exportInfoGenerator.BeginFeature(feature, display)
End Sub
Public Sub EndFeature(ByRef display As IDisplay)
If m_exportInfoGenerator Is Nothing Then Exit Sub
m_exportInfoGenerator.EndFeature(display)
End Sub
End Class
<ComClass(SortCallBack.ClassId, SortCallBack.InterfaceId, SortCallBack.EventsId)> _
Public Class SortCallBack ' would like to declare this as private
' class definition for SortCallBack which implements custom table sorting based on field / normalization field
Implements ITableSortCallBack
#Region "COM GUIDs"
' These GUIDs provide the COM identity for this class
' and its COM interfaces. If you change them, existing
' clients will no longer be able to access the class.
Public Const ClassId As String = "13137B0F-2255-46a4-9D6E-0A68FA560379"
Public Const InterfaceId As String = "68A049DC-8E6C-4759-9797-960076474729"
Public Const EventsId As String = "7BE0E19F-9AB3-4dd4-BB79-6EBD85E7930E"
#End Region
' data members
Private m_value1 As VariantType
Private m_value2 As VariantType
Private m_iValueIndex As Integer
Private m_iNormIndex As Integer
Public Sub New(ByVal ValueIndex As Integer, ByVal NormIndex As Integer)
m_iValueIndex = ValueIndex
m_iNormIndex = NormIndex
End Sub
Public Function Compare(ByVal value1 As Object, ByVal value2 As Object, ByVal FieldIndex As Integer, ByVal fieldSortIndex As Integer) As Integer Implements ITableSortCallBack.Compare
' sort normalized values
If (FieldIndex = m_iValueIndex) Then
m_value1 = value1
m_value2 = value2
Exit Function ' ?
End If
If (FieldIndex = m_iNormIndex) Then
If (value1 = 0) Or (value2 = 0) Then Exit Function ' ?
Dim dblNormedVal1 As Double
Dim dblNormedVal2 As Double
dblNormedVal1 = m_value1 / value1
dblNormedVal2 = m_value2 / value2
If dblNormedVal1 > dblNormedVal2 Then
Compare = 1
ElseIf dblNormedVal1 < dblNormedVal2 Then
Compare = -1
Else
Compare = 0
End If
End If
End Function
End Class