在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"); }
代码详解:
// 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);
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); }
// 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); } }
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); }
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; }
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. }
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."); } }