private void CreateAndPopulateTurnFeatureClass(string outputFileGdbPath, string fdsName, string ProhibRdmsTableName, string tempStatsTableName, IGPMessages messages, ITrackCancel trackcancel) { // Determine the number of AltID fields we need (one more than the MAX_SEQ_NUMBER value). Type factoryType = Type.GetTypeFromProgID("esriDataSourcesGDB.FileGDBWorkspaceFactory"); var wsf = Activator.CreateInstance(factoryType) as IWorkspaceFactory; var fws = wsf.OpenFromFile(outputFileGdbPath, 0) as IFeatureWorkspace; ITable tempStatsTable = fws.OpenTable(tempStatsTableName); short numAltIDFields = 2; if (tempStatsTable.RowCount(null) == 1) numAltIDFields = (short)(1 + (double)(tempStatsTable.GetRow(1).get_Value(tempStatsTable.FindField("MAX_SEQ_NUMBER")))); // Open the Rdms table and find the fields we need ITable rdmsTable = fws.OpenTable(ProhibRdmsTableName); int seqNumberField = rdmsTable.FindField("SEQ_NUMBER"); int linkIDFieldOnRdms = rdmsTable.FindField("LINK_ID"); int manLinkIDField = rdmsTable.FindField("MAN_LINKID"); int condIDFieldOnRdms = rdmsTable.FindField("COND_ID"); int endOfLkFieldOnRdms = rdmsTable.FindField("END_OF_LK"); // Create a temporary template feature class var fcd = new FeatureClassDescriptionClass() as IFeatureClassDescription; var ocd = fcd as IObjectClassDescription; var fieldsEdit = ocd.RequiredFields as IFieldsEdit; IField fieldOnRdmsTable = rdmsTable.Fields.get_Field(linkIDFieldOnRdms); // use the LINK_ID field as a template for the AltID fields for (short i = 1; i <= numAltIDFields; i++) { IFieldEdit newField = new FieldClass(); newField.Name_2 = "AltID" + i; newField.Precision_2 = fieldOnRdmsTable.Precision; newField.Scale_2 = fieldOnRdmsTable.Scale; newField.Type_2 = fieldOnRdmsTable.Type; fieldsEdit.AddField(newField as IField); } fieldOnRdmsTable = rdmsTable.Fields.get_Field(condIDFieldOnRdms); fieldsEdit.AddField(fieldOnRdmsTable); var fieldChk = new FieldCheckerClass() as IFieldChecker; IEnumFieldError enumFieldErr = null; IFields validatedFields = null; fieldChk.ValidateWorkspace = fws as IWorkspace; fieldChk.Validate(fieldsEdit as IFields, out enumFieldErr, out validatedFields); var tempFC = fws.CreateFeatureClass("TheTemplate", validatedFields, ocd.InstanceCLSID, ocd.ClassExtensionCLSID, esriFeatureType.esriFTSimple, fcd.ShapeFieldName, "") as IDataset; // Create the turn feature class from the template, then delete the template Geoprocessor gp = new Geoprocessor(); CreateTurnFeatureClass createTurnFCTool = new CreateTurnFeatureClass(); string pathToFds = outputFileGdbPath + "\\" + fdsName; createTurnFCTool.out_location = pathToFds; createTurnFCTool.out_feature_class_name = TurnFCName; createTurnFCTool.maximum_edges = numAltIDFields; createTurnFCTool.in_template_feature_class = outputFileGdbPath + "\\TheTemplate"; gp.Execute(createTurnFCTool, trackcancel); tempFC.Delete(); // Open the new turn feature class and find all the fields on it IFeatureClass turnFC = fws.OpenFeatureClass(TurnFCName); int[] altIDFields = new int[numAltIDFields]; int[] edgeFCIDFields = new int[numAltIDFields]; int[] edgeFIDFields = new int[numAltIDFields]; int[] edgePosFields = new int[numAltIDFields]; for (short i = 0; i < numAltIDFields; i++) { altIDFields[i] = turnFC.FindField("AltID" + (i + 1)); edgeFCIDFields[i] = turnFC.FindField("Edge" + (i + 1) + "FCID"); edgeFIDFields[i] = turnFC.FindField("Edge" + (i + 1) + "FID"); edgePosFields[i] = turnFC.FindField("Edge" + (i + 1) + "Pos"); } int edge1endField = turnFC.FindField("Edge1End"); int condIDFieldOnTurnFC = turnFC.FindField("COND_ID"); // Look up the FCID of the Streets feature class IFeatureClass streetsFC = fws.OpenFeatureClass(StreetsFCName); int streetsFCID = streetsFC.FeatureClassID; // Set up queries var ts = new TableSortClass() as ITableSort; ts.Fields = "COND_ID, SEQ_NUMBER"; ts.set_Ascending("COND_ID", true); ts.set_Ascending("SEQ_NUMBER", true); ts.QueryFilter = new QueryFilterClass(); ts.Table = rdmsTable; ts.Sort(null); ICursor rdmsCursor = ts.Rows; IFeatureCursor turnFCCursor = turnFC.Insert(true); IFeatureBuffer turnBuffer = turnFC.CreateFeatureBuffer(); // Write the field values to the turn feature class accordingly int numFeatures = 0; IRow rdmsRow = rdmsCursor.NextRow(); while (rdmsRow != null) { // Transfer the non-edge identifying field values to the buffer turnBuffer.set_Value(condIDFieldOnTurnFC, rdmsRow.get_Value(condIDFieldOnRdms)); // Write the Edge1End field value to the buffer switch ((string)(rdmsRow.get_Value(endOfLkFieldOnRdms))) { case "N": turnBuffer.set_Value(edge1endField, "Y"); break; case "R": turnBuffer.set_Value(edge1endField, "N"); break; default: break; // not expected } // Write the AltID values to the buffer turnBuffer.set_Value(altIDFields[0], rdmsRow.get_Value(linkIDFieldOnRdms)); short seq = (short)(rdmsRow.get_Value(seqNumberField)); short lastEntry; do { lastEntry = seq; turnBuffer.set_Value(altIDFields[lastEntry], rdmsRow.get_Value(manLinkIDField)); rdmsRow = rdmsCursor.NextRow(); if (rdmsRow == null) break; seq = (short)(rdmsRow.get_Value(seqNumberField)); } while (seq != 1); // Zero-out the unused fields for (int i = lastEntry + 1; i < numAltIDFields; i++) turnBuffer.set_Value(altIDFields[i], 0); // Write the FCID and Pos field values to the buffer for (short i = 0; i < numAltIDFields; i++) { int altID = (int)(turnBuffer.get_Value(altIDFields[i])); if (altID != 0) { turnBuffer.set_Value(edgeFCIDFields[i], streetsFCID); turnBuffer.set_Value(edgeFIDFields[i], 1); turnBuffer.set_Value(edgePosFields[i], 0.5); } else { turnBuffer.set_Value(edgeFCIDFields[i], 0); turnBuffer.set_Value(edgeFIDFields[i], 0); turnBuffer.set_Value(edgePosFields[i], 0); } } // Create the turn feature turnFCCursor.InsertFeature(turnBuffer); numFeatures++; if ((numFeatures % 100) == 0) { // check for user cancel if (trackcancel != null && !trackcancel.Continue()) throw (new COMException("Function cancelled.")); } } // Flush any outstanding writes to the turn feature class turnFCCursor.Flush(); messages.AddMessage("Updating the EdgeFID values..."); // Create a temporary network dataset for updating the EdgeFID values IDENetworkDataset dends = new DENetworkDatasetClass(); dends.SupportsTurns = true; dends.Buildable = true; (dends as IDataElement).Name = StreetsFCName; (dends as IDEGeoDataset).SpatialReference = (streetsFC as IGeoDataset).SpatialReference; IArray sourceArray = new ArrayClass(); var efs = new EdgeFeatureSourceClass() as IEdgeFeatureSource; (efs as INetworkSource).Name = StreetsFCName; efs.UsesSubtypes = false; efs.ClassConnectivityGroup = 1; efs.ClassConnectivityPolicy = esriNetworkEdgeConnectivityPolicy.esriNECPEndVertex; sourceArray.Add(efs); var tfs = new TurnFeatureSourceClass() as INetworkSource; tfs.Name = TurnFCName; sourceArray.Add(tfs); dends.Sources = sourceArray; var fdxc = fws.OpenFeatureDataset(fdsName) as IFeatureDatasetExtensionContainer; var dsCont = fdxc.FindExtension(esriDatasetType.esriDTNetworkDataset) as IDatasetContainer2; var tempNDS = dsCont.CreateDataset(dends as IDEDataset) as IDataset; // Set the EdgeFID field values by running UpdateByAlternateIDFields UpdateByAlternateIDFields updateByAltIDTool = new UpdateByAlternateIDFields(); updateByAltIDTool.in_network_dataset = pathToFds + "\\" + StreetsFCName; updateByAltIDTool.alternate_ID_field_name = "LINK_ID"; gp.Execute(updateByAltIDTool, trackcancel); // Delete the temporary network dataset tempNDS.Delete(); // Write the turn geometries TurnGeometryUtilities.WriteTurnGeometry(outputFileGdbPath, StreetsFCName, TurnFCName, numAltIDFields, 0.3, messages, trackcancel); // Index the turn geometries messages.AddMessage("Creating spatial index on the turn feature class..."); AddSpatialIndex addSpatialIndexTool = new AddSpatialIndex(); addSpatialIndexTool.in_features = pathToFds + "\\" + TurnFCName; gp.Execute(addSpatialIndexTool, trackcancel); return; }
private void CreateAndPopulateTurnFeatureClass(string outputFileGdbPath, string fdsName, string ProhibMPTableName, string tempStatsTableName, IGPMessages messages, ITrackCancel trackcancel) { // Determine the number of AltID fields we need (the same as the MAX_SEQNR value). Type factoryType = Type.GetTypeFromProgID("esriDataSourcesGDB.FileGDBWorkspaceFactory"); var wsf = Activator.CreateInstance(factoryType) as IWorkspaceFactory; var fws = wsf.OpenFromFile(outputFileGdbPath, 0) as IFeatureWorkspace; ITable tempStatsTable = fws.OpenTable(tempStatsTableName); short numAltIDFields = 2; if (tempStatsTable.RowCount(null) == 1) numAltIDFields = (short)((double)(tempStatsTable.GetRow(1).get_Value(tempStatsTable.FindField("MAX_SEQNR")))); // Open the MP table and find the fields we need ITable mpTable = fws.OpenTable(ProhibMPTableName); int seqNrField = mpTable.FindField("SEQNR"); int trpElIDField = mpTable.FindField("TRPELID"); int idFieldOnMP = mpTable.FindField("ID"); int mpJnctIDField = mpTable.FindField("JNCTID"); // Create a temporary template feature class var fcd = new FeatureClassDescriptionClass() as IFeatureClassDescription; var ocd = fcd as IObjectClassDescription; var fieldsEdit = ocd.RequiredFields as IFieldsEdit; IField fieldOnMPTable = mpTable.Fields.get_Field(idFieldOnMP); // use the ID field as a template for the AltID fields for (short i = 1; i <= numAltIDFields; i++) { IFieldEdit newField = new FieldClass(); newField.Name_2 = "AltID" + i; newField.Precision_2 = fieldOnMPTable.Precision; newField.Scale_2 = fieldOnMPTable.Scale; newField.Type_2 = fieldOnMPTable.Type; fieldsEdit.AddField(newField as IField); } fieldsEdit.AddField(fieldOnMPTable); fieldOnMPTable = mpTable.Fields.get_Field(mpJnctIDField); fieldsEdit.AddField(fieldOnMPTable); var fieldChk = new FieldCheckerClass() as IFieldChecker; IEnumFieldError enumFieldErr = null; IFields validatedFields = null; fieldChk.ValidateWorkspace = fws as IWorkspace; fieldChk.Validate(fieldsEdit as IFields, out enumFieldErr, out validatedFields); var tempFC = fws.CreateFeatureClass("TheTemplate", validatedFields, ocd.InstanceCLSID, ocd.ClassExtensionCLSID, esriFeatureType.esriFTSimple, fcd.ShapeFieldName, "") as IDataset; // Create the turn feature class from the template, then delete the template Geoprocessor gp = new Geoprocessor(); CreateTurnFeatureClass createTurnFCTool = new CreateTurnFeatureClass(); string pathToFds = outputFileGdbPath + "\\" + fdsName; createTurnFCTool.out_location = pathToFds; createTurnFCTool.out_feature_class_name = TurnFCName; createTurnFCTool.maximum_edges = numAltIDFields; createTurnFCTool.in_template_feature_class = outputFileGdbPath + "\\TheTemplate"; gp.Execute(createTurnFCTool, trackcancel); tempFC.Delete(); // Open the new turn feature class and find all the fields on it IFeatureClass turnFC = fws.OpenFeatureClass(TurnFCName); int[] altIDFields = new int[numAltIDFields]; int[] edgeFCIDFields = new int[numAltIDFields]; int[] edgeFIDFields = new int[numAltIDFields]; int[] edgePosFields = new int[numAltIDFields]; for (short i = 0; i < numAltIDFields; i++) { altIDFields[i] = turnFC.FindField("AltID" + (i + 1)); edgeFCIDFields[i] = turnFC.FindField("Edge" + (i + 1) + "FCID"); edgeFIDFields[i] = turnFC.FindField("Edge" + (i + 1) + "FID"); edgePosFields[i] = turnFC.FindField("Edge" + (i + 1) + "Pos"); } int edge1endField = turnFC.FindField("Edge1End"); int idFieldOnTurnFC = turnFC.FindField("ID"); int turnFCJnctIDField = turnFC.FindField("JNCTID"); // Look up the FCID of the Streets feature class IFeatureClass streetsFC = fws.OpenFeatureClass(StreetsFCName); int streetsFCID = streetsFC.FeatureClassID; // Set up queries var ts = new TableSortClass() as ITableSort; ts.Fields = "ID, SEQNR"; ts.set_Ascending("ID", true); ts.set_Ascending("SEQNR", true); ts.QueryFilter = new QueryFilterClass(); ts.Table = mpTable; ts.Sort(null); ICursor mpCursor = ts.Rows; IFeatureCursor turnFCCursor = turnFC.Insert(true); IFeatureBuffer turnBuffer = turnFC.CreateFeatureBuffer(); // Write the field values to the turn feature class accordingly turnBuffer.set_Value(edge1endField, "?"); // dummy value; will be updated in a later calculation int numFeatures = 0; IRow mpRow = mpCursor.NextRow(); while (mpRow != null) { // Transfer the non-edge identifying field values to the buffer turnBuffer.set_Value(idFieldOnTurnFC, mpRow.get_Value(idFieldOnMP)); turnBuffer.set_Value(turnFCJnctIDField, mpRow.get_Value(mpJnctIDField)); // Write the AltID values to the buffer int seq = (int)(mpRow.get_Value(seqNrField)); int lastEntry; do { lastEntry = seq; turnBuffer.set_Value(altIDFields[lastEntry - 1], mpRow.get_Value(trpElIDField)); mpRow = mpCursor.NextRow(); if (mpRow == null) break; seq = (int)(mpRow.get_Value(seqNrField)); } while (seq != 1); // Zero-out the unused fields for (int i = lastEntry; i < numAltIDFields; i++) turnBuffer.set_Value(altIDFields[i], 0); // Write the FCID and Pos field values to the buffer for (short i = 0; i < numAltIDFields; i++) { double altID = (double)(turnBuffer.get_Value(altIDFields[i])); if (altID != 0) { turnBuffer.set_Value(edgeFCIDFields[i], streetsFCID); turnBuffer.set_Value(edgeFIDFields[i], 1); turnBuffer.set_Value(edgePosFields[i], 0.5); } else { turnBuffer.set_Value(edgeFCIDFields[i], 0); turnBuffer.set_Value(edgeFIDFields[i], 0); turnBuffer.set_Value(edgePosFields[i], 0); } } // Create the turn feature turnFCCursor.InsertFeature(turnBuffer); numFeatures++; if ((numFeatures % 100) == 0) { // check for user cancel if (trackcancel != null && !trackcancel.Continue()) throw (new COMException("Function cancelled.")); } } // Flush any outstanding writes to the turn feature class turnFCCursor.Flush(); // Update the Edge1End values AddMessage("Updating the Edge1End values...", messages, trackcancel); MakeFeatureLayer makeFeatureLayerTool = new MakeFeatureLayer(); makeFeatureLayerTool.in_features = pathToFds + "\\" + TurnFCName; makeFeatureLayerTool.out_layer = "Turn_Layer"; gp.Execute(makeFeatureLayerTool, trackcancel); AddJoin addJoinTool = new AddJoin(); addJoinTool.in_layer_or_view = "Turn_Layer"; addJoinTool.in_field = "AltID1"; addJoinTool.join_table = pathToFds + "\\" + StreetsFCName; addJoinTool.join_field = "ID"; gp.Execute(addJoinTool, trackcancel); CalculateField calcFieldTool = new CalculateField(); calcFieldTool.in_table = "Turn_Layer"; calcFieldTool.field = TurnFCName + ".Edge1End"; calcFieldTool.expression = "x"; calcFieldTool.code_block = "Select Case [" + TurnFCName + ".JNCTID]\n Case [" + StreetsFCName + ".F_JNCTID]: x = \"N\"\n Case [" + StreetsFCName + ".T_JNCTID]: x = \"Y\"\n Case Else: x = \"?\"\nEnd Select"; calcFieldTool.expression_type = "VB"; gp.Execute(calcFieldTool, trackcancel); RemoveJoin removeJoinTool = new RemoveJoin(); removeJoinTool.in_layer_or_view = "Turn_Layer"; removeJoinTool.join_name = StreetsFCName; gp.Execute(removeJoinTool, trackcancel); Delete deleteTool = new Delete(); deleteTool.in_data = "Turn_Layer"; gp.Execute(deleteTool, trackcancel); AddMessage("Updating the EdgeFID values...", messages, trackcancel); // Create a temporary network dataset for updating the EdgeFID values IDENetworkDataset dends = new DENetworkDatasetClass(); dends.SupportsTurns = true; dends.Buildable = true; (dends as IDataElement).Name = StreetsFCName; (dends as IDEGeoDataset).SpatialReference = (streetsFC as IGeoDataset).SpatialReference; IArray sourceArray = new ArrayClass(); var efs = new EdgeFeatureSourceClass() as IEdgeFeatureSource; (efs as INetworkSource).Name = StreetsFCName; efs.UsesSubtypes = false; efs.ClassConnectivityGroup = 1; efs.ClassConnectivityPolicy = esriNetworkEdgeConnectivityPolicy.esriNECPEndVertex; sourceArray.Add(efs); var tfs = new TurnFeatureSourceClass() as INetworkSource; tfs.Name = TurnFCName; sourceArray.Add(tfs); dends.Sources = sourceArray; var fdxc = fws.OpenFeatureDataset(fdsName) as IFeatureDatasetExtensionContainer; var dsCont = fdxc.FindExtension(esriDatasetType.esriDTNetworkDataset) as IDatasetContainer2; var tempNDS = dsCont.CreateDataset(dends as IDEDataset) as IDataset; // Set the EdgeFID field values by running UpdateByAlternateIDFields UpdateByAlternateIDFields updateByAltIDTool = new UpdateByAlternateIDFields(); updateByAltIDTool.in_network_dataset = pathToFds + "\\" + StreetsFCName; updateByAltIDTool.alternate_ID_field_name = "ID"; gp.Execute(updateByAltIDTool, trackcancel); // Delete the temporary network dataset tempNDS.Delete(); // Write the turn geometries TurnGeometryUtilities.WriteTurnGeometry(outputFileGdbPath, StreetsFCName, TurnFCName, numAltIDFields, 0.3, messages, trackcancel); // Index the turn geometries AddMessage("Creating spatial index on the turn feature class...", messages, trackcancel); AddSpatialIndex addSpatialIndexTool = new AddSpatialIndex(); addSpatialIndexTool.in_features = pathToFds + "\\" + TurnFCName; gp.Execute(addSpatialIndexTool, trackcancel); return; }