在GIS数据管理中,涉及到多种分类的数据在同一个表中,表的属性列相同,但属性值可能有很大的区别,可以通过ArcGIS中的图层数据子类型进行管理,具体的应用方式如下,本实例通过ArcGIS10进行讲解,首先打开ArcCatalog,新建一个文件地理数据库。
图一
新建的文件地理数据库为test.gdb;在test.gdb中新建一个要素类
图二
这里新建一个线要素类
图三
增加属性列,包括subtype、name、domaintype、type等;
图四
建立完成之后,在该要素类上右键-〉属性;打开属性页,
图五
图六
切换到子类型页面
图七
选择子类型字段,子类型的字段,能够识别的类型为整型;
图八
选择相应的要分类的字段,之后根据业务类型,增加子类型;
图九
这里以电力为例,为线路管理要素类,设置4个子类型,分别为
编码 | 描述 |
0 | 高压电线 |
1 | 高压电缆 |
2 | 低压电线 |
3 | 低压电缆 |
可以设置默认的子类型,在进行数据编辑的时候,对于新增的数据默认类型为这个;
在子类型列表中,点击各个子类型,可以设置不同子类型的属性的默认值和属性域。
属性域,一般为key-value的形式,点击属性域按钮,可以对属性域进行设置
图十
可以对属性域进行新增、修改和删除;这里增加两个属性域一个为名称的属性域,一个为类型的属性域;
图十一
其中属性域类型为编码值的类型;如选择为整型,则填充除了整型之外的编码值;
图十二
点击确定,完成属性域的添加;
图十三
选择子类型中的高压电线,设置domaintype字段和type字段的属性域;点击确定,完成子类型和属性域的设置;接下来打开ArcMap,将该图层要素加载进去,进行编辑;
图十四
可以看到加载到ArcMap中去的要素类,自动分为了设置好的四个子类型的类;打开编辑器进行编辑;在创建要素类界面中可以看到不同子类型的要素。
图十五
设置不同类型的类型线路的图例,使得显示有意义;
图十六
增加一段低压电线;点击创建要素中的低压电线,在地图上添加;
图十七
进行属性编辑,发现domaintype和type字段中,没有下拉列表进行属性值的选择;
增加一段高压电线;点击创建要素中的高压电线,在地图上添加;
图十八
进行属性编辑,发现domaintype和type字段中,有下拉列表进行属性值的选择;
验证成功。
以上对于ArcGIS中的子类型和属性域进行了简单的介绍,该种应用方式对于较为复杂的空间数据应用比较好。
下面是用代码实现上述过程:
/// <summary>
/// 修改字段别名
/// </summary>
/// <param name="pTable">表</param>
/// <param name="strOriFieldName">待修改字段名称</param>
/// <param name="strDesFieldName">修改后别名</param>
public void ChangeFieldAliasName(ITable pTable, string strOriFieldName, string strDesFieldName)
{
IClassSchemaEdit pClassSchemaEdit = pTable as IClassSchemaEdit;
ISchemaLock pSchemaLock = (ISchemaLock)pTable;
pSchemaLock.ChangeSchemaLock(esriSchemaLock.esriExclusiveSchemaLock);
if (pTable.FindField(strOriFieldName) != -1)
{
pClassSchemaEdit.AlterFieldAliasName(strOriFieldName, strDesFieldName);
pSchemaLock.ChangeSchemaLock(esriSchemaLock.esriSharedSchemaLock);
}
else
{
return;
}
}
/// <summary>
/// 创建属性域
/// </summary>
/// <param name="pWs">工作空间</param>
/// <param name="strDomainName">属性域名称</param>
/// <param name="dicDomainItems">属性域的项</param>
public void CreateDomain(IWorkspace pWs,string strDomainName,Dictionary<string,string> dicDomainItems)
{
IWorkspaceDomains pWsDomains = (IWorkspaceDomains)pWs;
ICodedValueDomain pCodeValueDomain = new CodedValueDomainClass();
范围属性域只适用于数值字段
//IRangeDomain pRangeDomain = new RangeDomainClass();
foreach (KeyValuePair<string, string> domainItem in dicDomainItems)
{
pCodeValueDomain.AddCode(domainItem.Key, domainItem.Value);
}
IDomain pDomain = (IDomain)pCodeValueDomain;
pDomain.Name = strDomainName;
pDomain.FieldType = esriFieldType.esriFieldTypeString;
pDomain.SplitPolicy = esriSplitPolicyType.esriSPTDuplicate;
pDomain.MergePolicy = esriMergePolicyType.esriMPTDefaultValue;
pWsDomains.AddDomain(pDomain);
}
/// <summary>
/// 创建子类
/// </summary>
/// <param name="pFeaCls">要素</param>
/// <param name="strSubTypeFieldName">需创建子类的字段名</param>
/// <param name="dicSubtypeItems">子类项</param>
public void CreateSubtypes(IFeatureClass pFeaCls,string strSubTypeFieldName,Dictionary<int,string> dicSubtypeItems)
{
ISubtypes pSubtypes = pFeaCls as ISubtypes;
pSubtypes.SubtypeFieldName = strSubTypeFieldName;
foreach (KeyValuePair<int, string> subtypeItem in dicSubtypeItems)
{
pSubtypes.AddSubtype(subtypeItem.Key, subtypeItem.Value);
}
pSubtypes.DefaultSubtypeCode = 0;
}
/// <summary>
/// 将子类赋予属性域
/// </summary>
/// <param name="pFeatureClass">要素</param>
/// <param name="strDomainName">属性域</param>
/// <param name="iSubtypeNumber">子类编号</param>
/// <param name="strSetFieldName">赋予属性域的字段名</param>
public void AssignDomainToFieldWithSubtypes(IFeatureClass pFeatureClass, string strDomainName, int iSubtypeNumber, string strSetFieldName)
{
IDataset pDataset = (IDataset)pFeatureClass;
IWorkspace pWs = pDataset.Workspace;
IWorkspaceDomains pWsDomains = pWs as IWorkspaceDomains;
IDomain pDistributionDiamDomain = pWsDomains.get_DomainByName(strDomainName);
ISubtypes pSubtypes = pFeatureClass as ISubtypes;
pSubtypes.set_Domain(iSubtypeNumber, strSetFieldName, pDistributionDiamDomain);
}
private void BtnBegin_Click(object sender, EventArgs e)
{
IWorkspaceFactory pWsF = new AccessWorkspaceFactoryClass();
IWorkspace pWs = pWsF.OpenFromFile(@"C:\Users\ZhangHao\Desktop\属性域示例\系统支撑库.mdb", 0);
IFeatureClass pFeaCls = (pWs as IFeatureWorkspace).OpenFeatureClass("test");
Dictionary<int,string> dicSubtype=new Dictionary<int,string>();
dicSubtype.Add(0,"高压电线");
dicSubtype.Add(1, "高压电缆");
dicSubtype.Add(2, "低压电线");
dicSubtype.Add(3, "低压电缆");
CreateSubtypes(pFeaCls, "subtype", dicSubtype);
Dictionary<string, string> dicDomain = new Dictionary<string, string>();
dicDomain.Add("和平区","和平区高压电线");
dicDomain.Add("铁西区", "铁西区高压电线");
dicDomain.Add("沈河区", "沈河区高压电线");
dicDomain.Add("皇姑区", "皇姑区高压电线");
CreateDomain(pWs, "name_type_domain", dicDomain);
AssignDomainToFieldWithSubtypes(pFeaCls, "name_type_domain", 0, "domaintype");
}
代码详解:
1.Creating domains
// Cast the workspace to the IWorkspaceDomains interface.
IWorkspaceDomains workspaceDomains = (IWorkspaceDomains)workspace;
// The code to create a range domain.
IRangeDomain rangeDomain = new RangeDomainClass();
rangeDomain.MinValue = 0;
rangeDomain.MaxValue = 255;
// The code to set the common properties for the new range domain.
IDomain domain = (IDomain)rangeDomain;
domain.Name = "EightBitUnsignedInt";
domain.FieldType = esriFieldType.esriFieldTypeInteger;
domain.SplitPolicy = esriSplitPolicyType.esriSPTDuplicate;
domain.MergePolicy = esriMergePolicyType.esriMPTAreaWeighted;
// Add the new domain to the workspace.
workspaceDomains.AddDomain(domain);
// Cast the workspace to the IWorkspaceDomains interface.
IWorkspaceDomains workspaceDomains = (IWorkspaceDomains)workspace;
// The code to create a coded value domain.
ICodedValueDomain codedValueDomain = new CodedValueDomainClass();
// Value and name pairs.
codedValueDomain.AddCode("RES", "Residential");
codedValueDomain.AddCode("COM", "Commercial");
codedValueDomain.AddCode("IND", "Industrial");
codedValueDomain.AddCode("BLD", "Building");
// To remove a value:
codedValueDomain.DeleteCode("BLD"); // The "Building" code is removed.
// The code to set the common properties for the new coded value domain.
IDomain domain = (IDomain)codedValueDomain;
domain.Name = "Building Types";
domain.FieldType = esriFieldType.esriFieldTypeString;
domain.SplitPolicy = esriSplitPolicyType.esriSPTDuplicate;
domain.MergePolicy = esriMergePolicyType.esriMPTDefaultValue;
// Add the new domain to the workspace.
workspaceDomains.AddDomain(domain);
2.Opening and modifying domains
IWorkspaceDomains workspaceDomains = (IWorkspaceDomains)workspace;
IDomain requestedDomain = workspaceDomains.get_DomainByName(domainName);
Console.WriteLine("Valid values for domain '{0}':", domain.Name);
if (domain.Type == esriDomainType.esriDTCodedValue)
{
ICodedValueDomain codedValueDomain = (ICodedValueDomain)domain;
for (int i = 0; i < codedValueDomain.CodeCount; i++)
{
// codedValueDomain.get_Value(i) returns the code that is stored in the geodatabase
// (for example, RES).
// codedValueDomain.get_Name(i) returns the name that is shown in the ArcMap
// inspector (for example, Residential).
Console.WriteLine("Code: {0} Name: {1}", codedValueDomain.get_Value(i),
codedValueDomain.get_Name(i));
}
}
else
{
IRangeDomain rangeDomain = (IRangeDomain)domain;
Console.WriteLine("Minimum Value: {0} Maximum Value: {1}", rangeDomain.MinValue,
rangeDomain.MaxValue);
}
3.Assigning domains to fields
Assigning domains to fields in an object or feature class without defined subtypes
// For example: domainName = "Material".
// fieldName = "CP_MATERIAL".
public void AssignDomainToField(IFeatureClass featureClass, String domainName,
String fieldName)
{
// Cast the feature class to IDataset to get a reference to the workspace.
IDataset dataset = (IDataset)featureClass;
// Get the workspace and cast it to the IWorkspaceDomains interface and get the requested domain.
IWorkspace workspace = dataset.Workspace;
IWorkspaceDomains workspaceDomains = (IWorkspaceDomains)workspace;
IDomain domain = workspaceDomains.get_DomainByName(domainName);
// Get the field to assign the domain to.
IFields fields = featureClass.Fields;
int fieldIndex = featureClass.FindField(fieldName);
IField field = fields.get_Field(fieldIndex);
// Check that the field and domain have the same field type.
if (field.Type == domain.FieldType)
{
// Cast the feature class to the ISchemaLock and IClassSchemaEdit interfaces.
ISchemaLock schemaLock = (ISchemaLock)featureClass;
IClassSchemaEdit classSchemaEdit = (IClassSchemaEdit)featureClass;
// Attempt to get an exclusive schema lock.
try
{
// Lock the class and alter the domain.
schemaLock.ChangeSchemaLock(esriSchemaLock.esriExclusiveSchemaLock);
classSchemaEdit.AlterDomain(fieldName, domain);
Console.WriteLine("The domain was successfully assigned.");
}
catch (Exception exc)
{
// Handle the exception in a way appropriate for the application.
Console.WriteLine(exc.Message);
}
finally
{
// Set the schema lock to be a shared lock.
schemaLock.ChangeSchemaLock(esriSchemaLock.esriSharedSchemaLock);
}
}
else
{
Console.WriteLine("The field and the domain have different field types: " +
"Field = {0}, Domain = {1}", field.Type, domain.FieldType);
}
}
Assigning domains to fields in an object or feature class with defined subtypes
public void AssignDomainToFieldWithSubtypes(IFeatureClass featureClass)
{
// Cast the feature class to IDataset to get a reference to the workspace.
IDataset dataset = (IDataset)featureClass;
// Get the workspace and cast it to the IWorkspaceDomains interface and get the requested domain.
IWorkspace workspace = dataset.Workspace;
IWorkspaceDomains workspaceDomains = (IWorkspaceDomains)workspace;
// Get the domains from the workspace.
IDomain distributionDiamDomain = workspaceDomains.get_DomainByName("DistDiam");
IDomain transmissionDiamDomain = workspaceDomains.get_DomainByName("TransDiam");
// Cast for ISubtypes.
ISubtypes subtypes = (ISubtypes)featureClass;
// Assign the domain to the SIZE_ONE field on the distribution main subtype.
subtypes.set_Domain(1, "SIZE_ONE", distributionDiamDomain);
// Assign the domain to the SIZE_ONE field on the transmission main subtype.
subtypes.set_Domain(2, "SIZE_ONE", transmissionDiamDomain);
}
4.Creating subtypes
Adding subtypes to a feature class
public void AddPipeSubtypes(IFeatureClass featureClass)
{
// Cast the feature class to the ISubtypes interface.
ISubtypes subtypes = (ISubtypes)featureClass;
// Assign "PipeType" as the subtype field.
subtypes.SubtypeFieldName = "PipeType";
// Add the subtypes.
subtypes.AddSubtype(1, "Primary");
subtypes.AddSubtype(2, "Secondary");
// Assign the default subtype code.
subtypes.DefaultSubtypeCode = 1;
}
Assigning domains and default values to fields at the subtype level
public void SetDefaultsForSubtypes(IWorkspaceDomains workspaceDomains, ISubtypes
subtypes)
{
// The Diameter field in this example is an esriFieldTypeString field while
// the Material field type is esriFieldTypeInteger.
// Set the default value for the Diameter field on the primary subtype to 12.
subtypes.set_DefaultValue(1, "Diameter", "12");
// Set the domain for the Material field on the primary subtype to be the
// PrimaryMaterials domain.
IDomain primaryMaterialsDomain = workspaceDomains.get_DomainByName(
"PrimaryMaterials");
subtypes.set_Domain(1, "Material", primaryMaterialsDomain);
// Assign remaining domains at the subtype level.
IDomain primaryDiametersDomain = workspaceDomains.get_DomainByName(
"PrimaryDiameters");
subtypes.set_Domain(1, "Diameter", primaryDiametersDomain);
IDomain secondaryDiametersDomain = workspaceDomains.get_DomainByName(
"SecondaryDiameters");
subtypes.set_Domain(2, "Diameter", secondaryDiametersDomain);
IDomain secondaryMaterialsDomain = workspaceDomains.get_DomainByName(
"SecondaryMaterials");
subtypes.set_Domain(2, "Material", secondaryMaterialsDomain);
// Assign the remaining default values at the subtype level.
subtypes.set_DefaultValue(1, "Material", 1);
// In this case, 1 represents the domain code for steel.
subtypes.set_DefaultValue(2, "Diameter", "4");
subtypes.set_DefaultValue(2, "Material", 2);
// In this case, 2 represents the domain code for copper.
}
Resetting subtypes codes
public void ResetSubtypes(IObjectClass objectClass)
{
ISubtypes subtypes = (ISubtypes)objectClass;
if (subtypes.HasSubtype)
{
// The Subtype field can be reset by assigning an empty string to SubtypeFieldName.
subtypes.SubtypeFieldName = "";
}
else
{
Console.WriteLine("The class has no subtype defined.");
}
}